Esempio n. 1
0
def check_python_eval(cmd, path):
    ds = Dataset(path).create()
    res = ds.foreach_dataset(cmd, cmd_type='eval')
    eq_(len(res), 1)
    expected_variables = {'ds', 'pwd', 'refds'}
    eq_(expected_variables.intersection(res[0]['result']), expected_variables)
    # besides expected, there could be few more ATM, +5 arbitrarily just to test
    # that we are not leaking too much
    assert_greater(len(expected_variables) + 5, len(res[0]['result']))
Esempio n. 2
0
def _test_external(ev, modname):
    try:
        exec("import %s" % modname, globals(), locals())
    except ImportError:
        raise SkipTest("External %s not present" % modname)
    except Exception as e:
        raise SkipTest("External %s fails to import" % modname) from e
    assert (ev[modname] is not ev.UNKNOWN)
    assert_greater(ev[modname], '0.0.1')
    assert_greater('1000000.0', ev[modname])  # unlikely in our lifetimes
Esempio n. 3
0
def test__version__():
    # in released stage, version in the last CHANGELOG entry
    # should correspond to the one in datalad
    CHANGELOG_filename = op.join(
        op.dirname(__file__), op.pardir, op.pardir, 'CHANGELOG.md')
    if not op.exists(CHANGELOG_filename):
        raise SkipTest("no %s found" % CHANGELOG_filename)
    regex = re.compile(r'^# '
                       r'(?P<version>[0-9]+\.[0-9.abcrc~]+)\s+'
                       r'\((?P<date>.*)\)'
                       )
    with open(CHANGELOG_filename, 'rb') as f:
        for line in f:
            line = line.rstrip()
            if not line.startswith(b'# '):
                # The first section header we hit, must be our changelog entry
                continue
            reg = regex.match(ensure_unicode(line))
            if not reg:  # first one at that level is the one
                raise AssertionError(
                    "Following line must have matched our regex: %r" % line)
            regd = reg.groupdict()
            changelog_version = regd['version']
            lv_changelog_version = Version(changelog_version)
            # we might have a suffix - sanitize
            san__version__ = __version__.rstrip('.dirty')
            lv__version__ = Version(san__version__)
            if '???' in regd['date'] and 'will be better than ever' in regd['codename']:
                # we only have our template
                # we can only assert that its version should be higher than
                # the one we have now
                assert_greater(lv_changelog_version, lv__version__)
            else:
                # should be a "release" record
                assert_not_in('???', regd['date'])
                ok_startswith(__version__, changelog_version)
                if lv__version__ != lv_changelog_version:
                    # It was not tagged yet and Changelog has no new records
                    # (they are composed by auto upon release)
                    assert_greater(lv__version__, lv_changelog_version)
                    assert_in('+', san__version__)  # we have build suffix
                else:
                    # all is good, tagged etc
                    assert_equal(lv_changelog_version, lv__version__)
                    assert_equal(changelog_version, san__version__)
            return

    raise AssertionError(
        "No log line matching our regex found in %s" % CHANGELOG_filename
    )
Esempio n. 4
0
def test_external_versions_basic():
    ev = ExternalVersions()
    our_module = 'datalad'
    assert_equal(ev.versions, {})
    assert_equal(ev[our_module], __version__)
    # and it could be compared
    assert_greater_equal(ev[our_module], __version__)
    # We got some odd failure in this test not long are after switching to versionner
    # https://github.com/datalad/datalad/issues/5785.  Verify that we do get expected
    # data types
    our_version = ev[our_module].version
    assert isinstance(
        our_version,
        (str, list)), f"Got {our_version!r} of type {type(our_version)}"
    assert_greater(ev[our_module], '0.1')
    assert_equal(list(ev.keys()), [our_module])
    assert_true(our_module in ev)
    assert_false('unknown' in ev)

    # all are LooseVersions now
    assert_true(isinstance(ev[our_module], LooseVersion))
    version_str = __version__
    assert_equal(ev.dumps(), "Versions: %s=%s" % (our_module, version_str))

    # For non-existing one we get None
    assert_equal(ev['custom__nonexisting'], None)
    # and nothing gets added to _versions for nonexisting
    assert_equal(set(ev.versions.keys()), {our_module})

    # but if it is a module without version, we get it set to UNKNOWN
    assert_equal(ev['os'], ev.UNKNOWN)
    # And get a record on that inside
    assert_equal(ev.versions.get('os'), ev.UNKNOWN)
    # And that thing is "True", i.e. present
    assert (ev['os'])
    # but not comparable with anything besides itself (was above)
    assert_raises(TypeError, cmp, ev['os'], '0')
    assert_raises(TypeError, assert_greater, ev['os'], '0')

    return
Esempio n. 5
0
def test_try_lock_informatively(tempfile=None):
    lock = InterProcessLock(tempfile + '.lck')
    lock_path = ensure_unicode(
        lock.path)  # can be bytes, complicates string formattingetc
    t0 = time()
    with try_lock_informatively(lock, purpose="happy life") as acquired:
        assert_true(lock.acquired)
        assert_true(acquired)
        assert_greater(
            2,
            time() -
            t0)  # should not take any notable time, we cannot be blocking
        """
        # InterProcessLock is not re-entrant so nesting should not be used, will result
        # in exception on release
        with try_lock_informatively(lock, timeouts=[dt, dt*2], proceed_unlocked=True) as acquired:
            assert_true(lock.acquired)  # due to outer cm
            assert_true(acquired)       # lock is reentrant apparently
        """
        # Let's try in a completely different subprocess
        runner = WitlessRunner(env=dict(
            os.environ, DATALAD_LOG_LEVEL='info', DATALAD_LOG_TARGET='stderr'))

        script1 = Path(tempfile + "-script1.py")
        script1_fmt = f"""
from fasteners import InterProcessLock
from time import time

from datalad.support.locking import try_lock_informatively

lock = InterProcessLock({lock_path!r})

with try_lock_informatively(lock, timeouts=[0.05, 0.15], proceed_unlocked={{proceed_unlocked}}) as acquired:
    print("Lock acquired=%s" % acquired)
"""
        script1.write_text(script1_fmt.format(proceed_unlocked=True))
        t0 = time()
        res = runner.run([sys.executable, str(script1)],
                         protocol=StdOutErrCapture)
        assert_in('Lock acquired=False', res['stdout'])
        assert_in(f'Failed to acquire lock at {lock_path} in 0.05',
                  res['stderr'])
        assert_in(f'Failed to acquire lock at {lock_path} in 0.15',
                  res['stderr'])
        assert_in('proceed without locking', res['stderr'])
        assert_greater(time() - t0, 0.19999)  # should wait for at least 0.2
        try:
            import psutil

            # PID does not correspond
            assert_in('Check following process: PID=', res['stderr'])
            assert_in(f'CWD={os.getcwd()} CMDLINE=', res['stderr'])
        except ImportError:
            pass  # psutil was not installed, cannot get list of files
        except AssertionError:
            # we must have had the other one then
            assert_in('failed to determine one', res['stderr'])
            if not on_osx:
                # so far we had only OSX reporting failing to get PIDs information
                # but if it is something else -- re-raise original exception
                raise

        # in 2nd case, lets try without proceeding unlocked
        script1.write_text(script1_fmt.format(proceed_unlocked=False))
        t0 = time()
        with assert_raises(CommandError) as cme:
            runner.run([sys.executable, str(script1)],
                       protocol=StdOutErrCapture)
        assert_in(f"Failed to acquire lock at {lock_path} in 2 attempts.",
                  str(cme.value))
        assert_in(f"RuntimeError", str(cme.value))
        assert_false(
            cme.value.stdout)  # nothing there since print should not happen
        assert_in(f'Failed to acquire lock at {lock_path} in 0.05',
                  cme.value.stderr)
        assert_in(f'Failed to acquire lock at {lock_path} in 0.15',
                  cme.value.stderr)
        assert_greater(time() - t0, 0.19999)  # should wait for at least 0.2

    # now that we left context, should work out just fine
    res = runner.run([sys.executable, str(script1)], protocol=StdOutErrCapture)
    assert_in('Lock acquired=True', res['stdout'])
    assert_not_in(f'Failed to acquire lock', res['stderr'])
    assert_not_in('PID', res['stderr'])
Esempio n. 6
0
def test_wtf(topdir=None):
    path = opj(topdir, OBSCURE_FILENAME)
    # smoke test for now
    with swallow_outputs() as cmo:
        wtf(dataset=path, on_failure="ignore")
        assert_not_in('## dataset', cmo.out)
        assert_in('## configuration', cmo.out)
        # Those sections get sensored out by default now
        assert_not_in('user.name: ', cmo.out)
    with chpwd(path):
        with swallow_outputs() as cmo:
            wtf()
            assert_not_in('## dataset', cmo.out)
            assert_in('## configuration', cmo.out)
    # now with a dataset
    ds = create(path)
    with swallow_outputs() as cmo:
        wtf(dataset=ds.path)
        assert_in('## configuration', cmo.out)
        assert_in('## dataset', cmo.out)
        assert_in(u'path: {}'.format(ds.path), ensure_unicode(cmo.out))
        assert_in('branches', cmo.out)
        assert_in(DEFAULT_BRANCH + '@', cmo.out)
        assert_in('git-annex@', cmo.out)

    # and if we run with all sensitive
    for sensitive in ('some', True):
        with swallow_outputs() as cmo:
            wtf(dataset=ds.path, sensitive=sensitive)
            # we fake those for tests anyways, but we do show cfg in this mode
            # and explicitly not showing them
            assert_in('user.name: %s' % _HIDDEN, cmo.out)

    with swallow_outputs() as cmo:
        wtf(dataset=ds.path, sensitive='all')
        assert_not_in(_HIDDEN, cmo.out)  # all is shown
        assert_in('user.name: ', cmo.out)

    # Sections selection
    #
    # If we ask for no sections and there is no dataset
    with chpwd(path):
        with swallow_outputs() as cmo:
            wtf(sections=[])
            assert_not_in('## dataset', cmo.out)
            for s in SECTION_CALLABLES:
                assert_not_in('## %s' % s.lower(), cmo.out.lower())

    # ask for a selected set
    secs = ['git-annex', 'configuration']
    with chpwd(path):
        with swallow_outputs() as cmo:
            wtf(sections=secs)
            for s in SECTION_CALLABLES:
                (assert_in if s in secs else assert_not_in)('## %s' %
                                                            s.lower(),
                                                            cmo.out.lower())
            # order should match our desired one, not alphabetical
            # but because of https://github.com/datalad/datalad/issues/3915
            # alphanum is now desired
            assert cmo.out.index('## git-annex') > cmo.out.index(
                '## configuration')

    # not achievable from cmdline is to pass an empty list of sections.
    with chpwd(path):
        with swallow_outputs() as cmo:
            wtf(sections=[])
            eq_(cmo.out.rstrip(), '# WTF')

    # and we could decorate it nicely for embedding e.g. into github issues
    with swallow_outputs() as cmo:
        wtf(sections=['dependencies'], decor='html_details')
        ok_startswith(cmo.out,
                      '<details><summary>DataLad %s WTF' % __version__)
        assert_in('## dependencies', cmo.out)

    # short flavor
    with swallow_outputs() as cmo:
        wtf(flavor='short')
        assert_in("- datalad: version=%s" % __version__, cmo.out)
        assert_in("- dependencies: ", cmo.out)
        eq_(len(cmo.out.splitlines()),
            4)  # #WTF, datalad, dependencies, trailing new line

    with swallow_outputs() as cmo:
        wtf(flavor='short', sections='*')
        assert_greater(len(cmo.out.splitlines()), 10)  #  many more

    # check that wtf of an unavailable section yields impossible result (#6712)
    res = wtf(sections=['murkie'], on_failure='ignore')
    eq_(res[0]["status"], "impossible")

    # should result only in '# WTF'
    skip_if_no_module('pyperclip')

    # verify that it works correctly in the env/platform
    import pyperclip
    with swallow_outputs() as cmo:
        try:
            pyperclip.copy("xxx")
            pyperclip_works = pyperclip.paste().strip() == "xxx"
            wtf(dataset=ds.path, clipboard=True)
        except (AttributeError, pyperclip.PyperclipException) as exc:
            # AttributeError could come from pyperclip if no DISPLAY
            raise SkipTest(str(exc))
        assert_in("WTF information of length", cmo.out)
        assert_not_in('user.name', cmo.out)
        if not pyperclip_works:
            # Some times does not throw but just fails to work
            raise SkipTest(
                "Pyperclip seems to be not functioning here correctly")
        assert_not_in('user.name', pyperclip.paste())
        assert_in(_HIDDEN, pyperclip.paste())  # by default no sensitive info
        assert_in("cmd:annex:", pyperclip.paste())  # but the content is there
Esempio n. 7
0
def _test_list_tuple(thing):
    version = ExternalVersions._deduce_version(thing)
    assert_greater(version, '0.0.1')
    assert_greater('0.2', version)
    assert_equal('0.1', version)
    assert_equal(version, '0.1')
Esempio n. 8
0
def test_gracefull_death():
    def assert_provides_and_raises(pc, exception, target=None):
        """Helper to get all results before exception is raised"""
        results = []
        with assert_raises(exception):
            for r in pc:
                results.append(r)
        # results should be sorted since we do not guarantee order
        results = sorted(results)
        if target is not None:
            assert_equal(results, target)
        return results

    def interrupted_producer():
        yield 1
        raise ValueError()

    def consumer(i):
        sleep(0.001)
        yield i

    assert_provides_and_raises(
        ProducerConsumer(interrupted_producer(), consumer, jobs=3), ValueError,
        [1])

    def faulty_consumer(i):
        sleep(0.001)
        if i == 1:
            raise ValueError()
        return i

    # so we do not get failed, but other parallel ones finish their job
    results = assert_provides_and_raises(
        ProducerConsumer(range(1000), faulty_consumer, jobs=5), ValueError)
    # and analysis of futures to raise an exception can take some time etc, so
    # we could get more, but for sure we should not get all 999 and not even a 100
    if info_log_level:
        assert_greater(100, len(results))
    assert_equal(results[:4], [0, 2, 3, 4])

    def producer():
        for i in range(10):
            sleep(0.0003)
            yield i
        raise ValueError()

    # by default we do not stop upon producer failing
    assert_provides_and_raises(ProducerConsumer(producer(), consumer, jobs=2),
                               ValueError, list(range(10)))
    # if producer produces more than we can as quickly consume but then fails
    # ATM we do not proceed to consume other items, but fail when we finish
    # consuming until the time point when producer has failed
    # by default we do not stop upon producer failing
    results = assert_provides_and_raises(
        ProducerConsumer(producer(),
                         consumer,
                         reraise_immediately=True,
                         jobs=2), ValueError)
    # we will get some results, seems around 4 and they should be "sequential"
    assert_equal(results, list(range(len(results))))
    assert_greater_equal(len(results), 2)

    # This test relies too much on threads scheduling to not hog up on handling
    # consumers, but if it happens so - they might actually consume all results
    # before producer decides to finally raise an exception.  As such it remains
    # flaky and thus not ran, but could be useful to test locally while
    # changing that logic.
    #
    # if info_log_level and not (on_windows or on_osx):
    #     # consumers should not be able to consume all produced items.
    #     # production of 10 should take 3 unites, while consumers 10/2 (jobs)
    #     # 5 units, so some should not have a chance.
    #     assert_greater_equal(8, len(results))

    # Simulate situation close to what we have when outside code consumes
    # some yielded results and then "looses interest" (on_failure="error").
    # In this case we should still exit gracefully (no GeneratorExit warnings),
    # not over-produce, and also do not kill already running consumers
    consumed = []

    def inner():
        def consumer(i):
            sleep(0.01)
            consumed.append(i)
            return i

        pc = iter(ProducerConsumer(range(1000), consumer, jobs=2))
        yield next(pc)
        yield next(pc)

    assert_equal(sorted(inner()), [0, 1])
    consumed = sorted(consumed)
    assert_equal(consumed, list(range(len(consumed))))
    assert_greater_equal(len(consumed),
                         4)  # we should wait for that 2nd batch to finish
    if info_log_level:
        assert_greater_equal(20, len(consumed))