From 080cf82ebc5858ec47eff0d49bdf48b74f955274 Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Fri, 28 Oct 2022 22:37:29 +1300 Subject: MAINT: remove redundant open() modes and io.open() alias --- numpy/testing/_private/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 26b2aac4d..53930b78c 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -197,7 +197,7 @@ elif sys.platform[:5] == 'linux': """ try: - with open(_proc_pid_stat, 'r') as f: + with open(_proc_pid_stat) as f: l = f.readline().split(' ') return int(l[22]) except Exception: @@ -224,7 +224,7 @@ if sys.platform[:5] == 'linux': if not _load_time: _load_time.append(time.time()) try: - with open(_proc_pid_stat, 'r') as f: + with open(_proc_pid_stat) as f: l = f.readline().split(' ') return int(l[13]) except Exception: @@ -2545,7 +2545,7 @@ def _get_mem_available(): if sys.platform.startswith('linux'): info = {} - with open('/proc/meminfo', 'r') as f: + with open('/proc/meminfo') as f: for line in f: p = line.split() info[p[0].strip(':').lower()] = int(p[1]) * 1024 -- cgit v1.2.1 From 08c6e9c142e619ac5175b6a13342ba2f2c571ddd Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Thu, 10 Nov 2022 11:54:21 -0800 Subject: TST: Skip tests that are not currently supported in wasm --- numpy/testing/_private/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 26b2aac4d..ea1dc28b5 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -34,7 +34,7 @@ __all__ = [ 'assert_array_max_ulp', 'assert_warns', 'assert_no_warnings', 'assert_allclose', 'IgnoreException', 'clear_and_catch_warnings', 'SkipTest', 'KnownFailureException', 'temppath', 'tempdir', 'IS_PYPY', - 'HAS_REFCOUNT', 'suppress_warnings', 'assert_array_compare', + 'HAS_REFCOUNT', "IS_WASM", 'suppress_warnings', 'assert_array_compare', 'assert_no_gc_cycles', 'break_cycles', 'HAS_LAPACK64', 'IS_PYSTON', '_OLD_PROMOTION' ] @@ -48,6 +48,7 @@ class KnownFailureException(Exception): KnownFailureTest = KnownFailureException # backwards compat verbose = 0 +IS_WASM = platform.machine() in ["wasm32", "wasm64"] IS_PYPY = sys.implementation.name == 'pypy' IS_PYSTON = hasattr(sys, "pyston_version_info") HAS_REFCOUNT = getattr(sys, 'getrefcount', None) is not None and not IS_PYSTON -- cgit v1.2.1 From c6e75fce247d3d698ef76bb2c550858d32241268 Mon Sep 17 00:00:00 2001 From: warren Date: Fri, 18 Nov 2022 10:55:18 -0500 Subject: DOC: testing: Fix typo: nulps -> nulp [skip actions] [skip travis] [skip azp] --- numpy/testing/_private/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index ea1dc28b5..45400856b 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -1626,7 +1626,7 @@ def assert_array_almost_equal_nulp(x, y, nulp=1): ----- An assertion is raised if the following condition is not met:: - abs(x - y) <= nulps * spacing(maximum(abs(x), abs(y))) + abs(x - y) <= nulp * spacing(maximum(abs(x), abs(y))) Examples -------- -- cgit v1.2.1 From 4e710c5be093eb4367b4a08d9068f99f9070870d Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 16 Jan 2023 02:37:55 -0500 Subject: DOC: Add version added information for the strict parameter in assert_array_equal (#23015) --- numpy/testing/_private/utils.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 45400856b..2a2126503 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -899,6 +899,8 @@ def assert_array_equal(x, y, err_msg='', verbose=True, *, strict=False): type of the array_like objects does not match. The special handling for scalars mentioned in the Notes section is disabled. + .. versionadded:: 1.24.0 + Raises ------ AssertionError -- cgit v1.2.1 From f75bb0edb0e6eec2564de4bf798242984860a19b Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Wed, 18 Jan 2023 17:04:13 -0700 Subject: MAINT: Remove all nose testing support. NumPy switched to using pytest in 2018 and nose has been unmaintained for many years. We have kept NumPy's nose support to avoid breaking downstream projects who might have been using it and not yet switched to pytest or some other testing framework. With the arrival of Python 3.12, unpatched nose will raise an error. It it time to move on. Decorators removed - raises - slow - setastest - skipif - knownfailif - deprecated - parametrize - _needs_refcount These are not to be confused with pytest versions with similar names, e.g., pytest.mark.slow, pytest.mark.skipif, pytest.mark.parametrize. Functions removed - Tester - import_nose - run_module_suite --- numpy/testing/_private/utils.py | 61 +---------------------------------------- 1 file changed, 1 insertion(+), 60 deletions(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 2a2126503..351bd2a81 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -29,7 +29,7 @@ __all__ = [ 'assert_array_equal', 'assert_array_less', 'assert_string_equal', 'assert_array_almost_equal', 'assert_raises', 'build_err_msg', 'decorate_methods', 'jiffies', 'memusage', 'print_assert_equal', - 'raises', 'rundocs', 'runstring', 'verbose', 'measure', + 'rundocs', 'runstring', 'verbose', 'measure', 'assert_', 'assert_array_almost_equal_nulp', 'assert_raises_regex', 'assert_array_max_ulp', 'assert_warns', 'assert_no_warnings', 'assert_allclose', 'IgnoreException', 'clear_and_catch_warnings', @@ -57,28 +57,6 @@ HAS_LAPACK64 = numpy.linalg.lapack_lite._ilp64 _OLD_PROMOTION = lambda: np._get_promotion_state() == 'legacy' -def import_nose(): - """ Import nose only when needed. - """ - nose_is_good = True - minimum_nose_version = (1, 0, 0) - try: - import nose - except ImportError: - nose_is_good = False - else: - if nose.__versioninfo__ < minimum_nose_version: - nose_is_good = False - - if not nose_is_good: - msg = ('Need nose >= %d.%d.%d for tests - see ' - 'https://nose.readthedocs.io' % - minimum_nose_version) - raise ImportError(msg) - - return nose - - def assert_(val, msg=''): """ Assert that works in release mode. @@ -1305,43 +1283,6 @@ def rundocs(filename=None, raise_on_error=True): raise AssertionError("Some doctests failed:\n%s" % "\n".join(msg)) -def raises(*args): - """Decorator to check for raised exceptions. - - The decorated test function must raise one of the passed exceptions to - pass. If you want to test many assertions about exceptions in a single - test, you may want to use `assert_raises` instead. - - .. warning:: - This decorator is nose specific, do not use it if you are using a - different test framework. - - Parameters - ---------- - args : exceptions - The test passes if any of the passed exceptions is raised. - - Raises - ------ - AssertionError - - Examples - -------- - - Usage:: - - @raises(TypeError, ValueError) - def test_raises_type_error(): - raise TypeError("This test passes") - - @raises(Exception) - def test_that_fails_by_passing(): - pass - - """ - nose = import_nose() - return nose.tools.raises(*args) - # # assert_raises and assert_raises_regex are taken from unittest. # -- cgit v1.2.1 From df3751b03d789ee04cac3a9a8a7f7f3aba58735c Mon Sep 17 00:00:00 2001 From: Andrew Nelson Date: Sat, 21 Jan 2023 02:03:28 +1100 Subject: CI: musllinux_x86_64 (#22864) [ci skip] --- numpy/testing/_private/utils.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 351bd2a81..44092f185 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -16,6 +16,7 @@ from tempfile import mkdtemp, mkstemp from unittest.case import SkipTest from warnings import WarningMessage import pprint +import sysconfig import numpy as np from numpy.core import( @@ -36,7 +37,7 @@ __all__ = [ 'SkipTest', 'KnownFailureException', 'temppath', 'tempdir', 'IS_PYPY', 'HAS_REFCOUNT', "IS_WASM", 'suppress_warnings', 'assert_array_compare', 'assert_no_gc_cycles', 'break_cycles', 'HAS_LAPACK64', 'IS_PYSTON', - '_OLD_PROMOTION' + '_OLD_PROMOTION', 'IS_MUSL' ] @@ -56,6 +57,19 @@ HAS_LAPACK64 = numpy.linalg.lapack_lite._ilp64 _OLD_PROMOTION = lambda: np._get_promotion_state() == 'legacy' +IS_MUSL = False +try: + from packaging.tags import sys_tags + _tags = list(sys_tags()) + if 'musllinux' in _tags[0].platform: + IS_MUSL = True +except ImportError: + # fallback to sysconfig (might be flaky) + # value could be None. + v = sysconfig.get_config_var('HOST_GNU_TYPE') or '' + if 'musl' in v: + IS_MUSL = True + def assert_(val, msg=''): """ -- cgit v1.2.1 From abfaac73be054db5b3555315d56825d2e683e02f Mon Sep 17 00:00:00 2001 From: warren Date: Thu, 16 Feb 2023 07:14:32 -0500 Subject: MAINT: testing: Fix some whitespace and minor code issues in utils.py --- numpy/testing/_private/utils.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 44092f185..6ceea5771 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -19,7 +19,7 @@ import pprint import sysconfig import numpy as np -from numpy.core import( +from numpy.core import ( intp, float32, empty, arange, array_repr, ndarray, isnat, array) import numpy.linalg.lapack_lite @@ -470,7 +470,7 @@ def print_assert_equal(test_string, actual, desired): @np._no_nep50_warning() -def assert_almost_equal(actual,desired,decimal=7,err_msg='',verbose=True): +def assert_almost_equal(actual, desired, decimal=7, err_msg='', verbose=True): """ Raises an AssertionError if two items are not equal up to desired precision. @@ -597,7 +597,8 @@ def assert_almost_equal(actual,desired,decimal=7,err_msg='',verbose=True): @np._no_nep50_warning() -def assert_approx_equal(actual,desired,significant=7,err_msg='',verbose=True): +def assert_approx_equal(actual, desired, significant=7, err_msg='', + verbose=True): """ Raises an AssertionError if two items are not equal up to significant digits. @@ -701,7 +702,8 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, header='', precision=6, equal_nan=True, equal_inf=True, *, strict=False): __tracebackhide__ = True # Hide traceback for py.test - from numpy.core import array, array2string, isnan, inf, bool_, errstate, all, max, object_ + from numpy.core import (array2string, isnan, inf, bool_, errstate, + all, max, object_) x = np.asanyarray(x) y = np.asanyarray(y) @@ -827,10 +829,10 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, header='', max_abs_error = max(error) if getattr(error, 'dtype', object_) == object_: remarks.append('Max absolute difference: ' - + str(max_abs_error)) + + str(max_abs_error)) else: remarks.append('Max absolute difference: ' - + array2string(max_abs_error)) + + array2string(max_abs_error)) # note: this definition of relative error matches that one # used by assert_allclose (found in np.isclose) @@ -842,10 +844,10 @@ def assert_array_compare(comparison, x, y, err_msg='', verbose=True, header='', max_rel_error = max(error[nonzero] / abs(y[nonzero])) if getattr(error, 'dtype', object_) == object_: remarks.append('Max relative difference: ' - + str(max_rel_error)) + + str(max_rel_error)) else: remarks.append('Max relative difference: ' - + array2string(max_rel_error)) + + array2string(max_rel_error)) err_msg += '\n' + '\n'.join(remarks) msg = build_err_msg([ox, oy], err_msg, @@ -1058,13 +1060,13 @@ def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True): """ __tracebackhide__ = True # Hide traceback for py.test - from numpy.core import number, float_, result_type, array + from numpy.core import number, float_, result_type from numpy.core.numerictypes import issubdtype from numpy.core.fromnumeric import any as npany def compare(x, y): try: - if npany(gisinf(x)) or npany( gisinf(y)): + if npany(gisinf(x)) or npany(gisinf(y)): xinfid = gisinf(x) yinfid = gisinf(y) if not (xinfid == yinfid).all(): @@ -1106,8 +1108,6 @@ def assert_array_less(x, y, err_msg='', verbose=True): compared, no assertion is raised if both objects have NaNs in the same positions. - - Parameters ---------- x : array_like @@ -1129,8 +1129,6 @@ def assert_array_less(x, y, err_msg='', verbose=True): assert_array_equal: tests objects for equality assert_array_almost_equal: test objects for equality up to precision - - Examples -------- >>> np.testing.assert_array_less([1.0, 1.0, np.nan], [1.1, 2.0, np.nan]) @@ -1307,8 +1305,10 @@ class _Dummy(unittest.TestCase): def nop(self): pass + _d = _Dummy('nop') + def assert_raises(*args, **kwargs): """ assert_raises(exception_class, callable, *args, **kwargs) @@ -1335,7 +1335,7 @@ def assert_raises(*args, **kwargs): """ __tracebackhide__ = True # Hide traceback for py.test - return _d.assertRaises(*args,**kwargs) + return _d.assertRaises(*args, **kwargs) def assert_raises_regex(exception_class, expected_regexp, *args, **kwargs): @@ -1486,7 +1486,7 @@ def assert_allclose(actual, desired, rtol=1e-7, atol=0, equal_nan=True, Given two array_like objects, check that their shapes and all elements are equal (but see the Notes for the special handling of a scalar). An - exception is raised if the shapes mismatch or any values conflict. In + exception is raised if the shapes mismatch or any values conflict. In contrast to the standard usage in numpy, NaNs are compared like numbers, no assertion is raised if both objects have NaNs in the same positions. @@ -2408,6 +2408,7 @@ def assert_no_gc_cycles(*args, **kwargs): with _assert_no_gc_cycles_context(name=func.__name__): func(*args, **kwargs) + def break_cycles(): """ Break reference cycles by calling gc.collect @@ -2540,7 +2541,7 @@ def _no_tracing(func): def _get_glibc_version(): try: ver = os.confstr('CS_GNU_LIBC_VERSION').rsplit(' ')[1] - except Exception as inst: + except Exception: ver = '0.0' return ver -- cgit v1.2.1 From fccb005a6c995923d47aeda4e71a1d2a4a07f703 Mon Sep 17 00:00:00 2001 From: yamadafuyuka Date: Wed, 28 Dec 2022 12:59:07 +0900 Subject: ENH: add support for fujitsu C/C++ compiler and SSL2 to numpy. --- numpy/testing/_private/utils.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 44092f185..3ebc6a31f 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -37,7 +37,7 @@ __all__ = [ 'SkipTest', 'KnownFailureException', 'temppath', 'tempdir', 'IS_PYPY', 'HAS_REFCOUNT', "IS_WASM", 'suppress_warnings', 'assert_array_compare', 'assert_no_gc_cycles', 'break_cycles', 'HAS_LAPACK64', 'IS_PYSTON', - '_OLD_PROMOTION', 'IS_MUSL' + '_OLD_PROMOTION', 'IS_MUSL', '_SUPPORTS_SVE' ] @@ -1297,6 +1297,22 @@ def rundocs(filename=None, raise_on_error=True): raise AssertionError("Some doctests failed:\n%s" % "\n".join(msg)) +def check_support_sve(): + """ + gh-22982 + """ + + import subprocess + cmd = 'lscpu' + try: + return "sve" in (subprocess.Popen(cmd, stdout=subprocess.PIPE, + shell=True).communicate()[0]).decode('utf-8') + except OSError: + return False + + +_SUPPORTS_SVE = check_support_sve() + # # assert_raises and assert_raises_regex are taken from unittest. # @@ -2548,3 +2564,4 @@ def _get_glibc_version(): _glibcver = _get_glibc_version() _glibc_older_than = lambda x: (_glibcver != '0.0' and _glibcver < x) + -- cgit v1.2.1 From 57f5cf0501dac874dc2863e598272d7bf61f296e Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Wed, 3 May 2023 13:06:13 +0200 Subject: MAINT: Remove gisnan, gisinf, and gisfinite from testing code These were introduced many years ago when ufuncs were buggy and could return NotImplemented sometimes. This has been fixed for many years, though. I suspect the errstate for `isfinite` is not required so removed it. It was a 12+ year old work-around for warnings that really shouldn't happen to begin with. (The commit mentions `np.isinf(np.inf)` giving a warning, which doesn't make sense, I think.) --- numpy/testing/_private/utils.py | 81 +++++++---------------------------------- 1 file changed, 13 insertions(+), 68 deletions(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index f2fd9d2ae..8ef886cac 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -21,6 +21,7 @@ import sysconfig import numpy as np from numpy.core import ( intp, float32, empty, arange, array_repr, ndarray, isnat, array) +from numpy import isfinite, isnan, isinf import numpy.linalg.lapack_lite from io import StringIO @@ -91,62 +92,6 @@ def assert_(val, msg=''): raise AssertionError(smsg) -def gisnan(x): - """like isnan, but always raise an error if type not supported instead of - returning a TypeError object. - - Notes - ----- - isnan and other ufunc sometimes return a NotImplementedType object instead - of raising any exception. This function is a wrapper to make sure an - exception is always raised. - - This should be removed once this problem is solved at the Ufunc level.""" - from numpy.core import isnan - st = isnan(x) - if isinstance(st, type(NotImplemented)): - raise TypeError("isnan not supported for this type") - return st - - -def gisfinite(x): - """like isfinite, but always raise an error if type not supported instead - of returning a TypeError object. - - Notes - ----- - isfinite and other ufunc sometimes return a NotImplementedType object - instead of raising any exception. This function is a wrapper to make sure - an exception is always raised. - - This should be removed once this problem is solved at the Ufunc level.""" - from numpy.core import isfinite, errstate - with errstate(invalid='ignore'): - st = isfinite(x) - if isinstance(st, type(NotImplemented)): - raise TypeError("isfinite not supported for this type") - return st - - -def gisinf(x): - """like isinf, but always raise an error if type not supported instead of - returning a TypeError object. - - Notes - ----- - isinf and other ufunc sometimes return a NotImplementedType object instead - of raising any exception. This function is a wrapper to make sure an - exception is always raised. - - This should be removed once this problem is solved at the Ufunc level.""" - from numpy.core import isinf, errstate - with errstate(invalid='ignore'): - st = isinf(x) - if isinstance(st, type(NotImplemented)): - raise TypeError("isinf not supported for this type") - return st - - if os.name == 'nt': # Code "stolen" from enthought/debug/memusage.py def GetPerformanceAttributes(object, counter, instance=None, @@ -390,8 +335,8 @@ def assert_equal(actual, desired, err_msg='', verbose=True): # Inf/nan/negative zero handling try: - isdesnan = gisnan(desired) - isactnan = gisnan(actual) + isdesnan = isnan(desired) + isactnan = isnan(actual) if isdesnan and isactnan: return # both nan, so equal @@ -401,7 +346,7 @@ def assert_equal(actual, desired, err_msg='', verbose=True): if (array_actual.dtype.char in 'Mm' or array_desired.dtype.char in 'Mm'): # version 1.18 - # until this version, gisnan failed for datetime64 and timedelta64. + # until this version, isnan failed for datetime64 and timedelta64. # Now it succeeds but comparison to scalar with a different type # emits a DeprecationWarning. # Avoid that by skipping the next check @@ -582,9 +527,9 @@ def assert_almost_equal(actual, desired, decimal=7, err_msg='', verbose=True): # If one of desired/actual is not finite, handle it specially here: # check that both are nan if any is a nan, and test for equality # otherwise - if not (gisfinite(desired) and gisfinite(actual)): - if gisnan(desired) or gisnan(actual): - if not (gisnan(desired) and gisnan(actual)): + if not (isfinite(desired) and isfinite(actual)): + if isnan(desired) or isnan(actual): + if not (isnan(desired) and isnan(actual)): raise AssertionError(_build_err_msg()) else: if not desired == actual: @@ -683,9 +628,9 @@ def assert_approx_equal(actual, desired, significant=7, err_msg='', # If one of desired/actual is not finite, handle it specially here: # check that both are nan if any is a nan, and test for equality # otherwise - if not (gisfinite(desired) and gisfinite(actual)): - if gisnan(desired) or gisnan(actual): - if not (gisnan(desired) and gisnan(actual)): + if not (isfinite(desired) and isfinite(actual)): + if isnan(desired) or isnan(actual): + if not (isnan(desired) and isnan(actual)): raise AssertionError(msg) else: if not desired == actual: @@ -1066,9 +1011,9 @@ def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True): def compare(x, y): try: - if npany(gisinf(x)) or npany(gisinf(y)): - xinfid = gisinf(x) - yinfid = gisinf(y) + if npany(isinf(x)) or npany(isinf(y)): + xinfid = isinf(x) + yinfid = isinf(y) if not (xinfid == yinfid).all(): return False # if one item, x and y is +- inf -- cgit v1.2.1 From 291132113335d611a02fffcce5ce2f4b74c54802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Fri, 5 May 2023 23:14:44 +0200 Subject: DOC: fix incorrect description of raise condition in numpy.testing.assert_array_less's docstring --- numpy/testing/_private/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'numpy/testing/_private/utils.py') diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index 8ef886cac..cca7b8063 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -1067,7 +1067,7 @@ def assert_array_less(x, y, err_msg='', verbose=True): Raises ------ AssertionError - If actual and desired objects are not equal. + If x is not strictly smaller than y, element-wise. See Also -------- -- cgit v1.2.1