{
    "file_diffs": [
        {
            "old_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Tests for credentials\"\"\"\n\nfrom datalad.tests.utils import with_testsui\nfrom datalad.tests.utils import assert_equal\nfrom datalad.tests.utils import assert_true, assert_false\nfrom datalad.tests.utils import assert_raises\nfrom datalad.tests.utils import SkipTest\nfrom datalad.support.keyring_ import MemoryKeyring\nfrom ..credentials import UserPassword\nfrom ..credentials import CompositeCredential\n\n\n@with_testsui(responses=['user1', 'password1'])\ndef test_cred1_enter_new():\n    keyring = MemoryKeyring()\n    cred = UserPassword(\"name\", keyring=keyring)\n    assert_false(cred.is_known)\n    assert_equal(cred.enter_new(), None)\n    assert_true(cred.is_known)\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_equal(keyring.get('name', 'password'), 'password1')\n    keyring.delete('name')\n    assert_raises(KeyError, keyring.delete, 'name', 'user')\n    assert_raises(KeyError, keyring.delete, 'name')\n    assert_equal(keyring.get('name', 'user'), None)\n\n\n@with_testsui(responses=['password1'])\ndef test_cred1_call():\n    keyring = MemoryKeyring()\n    cred = UserPassword(\"name\", keyring=keyring)\n    # we will set the name but not the password, expecting UI\n    # requesting it\n    assert_equal(keyring.set('name', 'user', 'user1'), None)\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_equal(cred(), {'user': 'user1', 'password': 'password1'})\n    assert_equal(keyring.get('name', 'password'), 'password1')\n\n\ndef test_keyring():\n    # mock out keyring methods and test that we are providing correct values\n    # with 'datalad-' prefix\n    raise SkipTest(\"provide tests for Keyring which interfaces keyring module\")\n\n\ndef _cred1_adapter(user=None, password=None):\n    \"\"\"Just a sample adapter from one user/pw type to another\"\"\"\n    return dict(user=user + \"_1\", password=password + \"_2\")\n\n\nclass _CCred1(CompositeCredential):\n    \"\"\"A Simple composite credential which will do some entries transformation\n    \"\"\"\n    _CREDENTIAL_CLASSES = (UserPassword, UserPassword)\n    _CREDENTIAL_ADAPTERS = (_cred1_adapter,)\n\n\n@with_testsui(responses=['user1', 'password1',\n                         'user2', 'password2'])\ndef test_composite_credential1():\n    # basic test of composite credential\n    keyring = MemoryKeyring()\n    cred = _CCred1(\"name\", keyring=keyring)\n    # When queried, does the chain\n    assert_equal(cred(), {'user': 'user1_1', 'password': 'password1_2'})\n    # But the \"Front\" credential is exposed to the user\n    assert_equal(cred.get('user'), 'user1')\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_raises(ValueError, cred.get, 'unknown_field')\n    assert_equal(cred.get('password'), 'password1')\n    assert_equal(keyring.get('name', 'password'), 'password1')\n    # ATM composite credential stores \"derived\" ones unconditionally in the\n    # keyring as well\n    assert_equal(keyring.get('name:1', 'user'), 'user1_1')\n    assert_equal(keyring.get('name:1', 'password'), 'password1_2')\n\n    # and now enter new should remove \"derived\" entries\n    cred.enter_new()\n    assert_equal(keyring.get('name', 'user'), 'user2')\n    assert_equal(keyring.get('name', 'password'), 'password2')\n    assert_equal(keyring.get('name:1', 'user'), None)\n    assert_equal(keyring.get('name:1', 'password'), None)\n    # which would get reevaluated if requested\n    assert_equal(keyring.entries, {'name:1': {}, 'name': {'user': 'user2', 'password': 'password2'}})\n    assert_equal(cred(), {'user': 'user2_1', 'password': 'password2_2'})\n",
            "new_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Tests for credentials\"\"\"\n\nfrom mock import patch\n\nfrom datalad.tests.utils import with_testsui\nfrom datalad.tests.utils import assert_equal\nfrom datalad.tests.utils import assert_true, assert_false\nfrom datalad.tests.utils import assert_raises\nfrom datalad.tests.utils import SkipTest\nfrom datalad.support.keyring_ import MemoryKeyring\nfrom datalad.support.keyring_ import Keyring\nfrom ..credentials import UserPassword\nfrom ..credentials import CompositeCredential\nfrom ..credentials import AWS_S3\n\n\n@with_testsui(responses=['user1', 'password1'])\ndef test_cred1_enter_new():\n    keyring = MemoryKeyring()\n    cred = UserPassword(\"name\", keyring=keyring)\n    assert_false(cred.is_known)\n    assert_equal(cred.enter_new(), None)\n    assert_true(cred.is_known)\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_equal(keyring.get('name', 'password'), 'password1')\n    keyring.delete('name')\n    assert_raises(KeyError, keyring.delete, 'name', 'user')\n    assert_raises(KeyError, keyring.delete, 'name')\n    assert_equal(keyring.get('name', 'user'), None)\n\n\n@with_testsui(responses=['password1'])\ndef test_cred1_call():\n    keyring = MemoryKeyring()\n    cred = UserPassword(\"name\", keyring=keyring)\n    # we will set the name but not the password, expecting UI\n    # requesting it\n    assert_equal(keyring.set('name', 'user', 'user1'), None)\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_equal(cred(), {'user': 'user1', 'password': 'password1'})\n    assert_equal(keyring.get('name', 'password'), 'password1')\n\n\ndef test_keyring():\n    # mock out keyring methods and test that we are providing correct values\n    # with 'datalad-' prefix\n    raise SkipTest(\"provide tests for Keyring which interfaces keyring module\")\n\n\ndef _cred1_adapter(user=None, password=None):\n    \"\"\"Just a sample adapter from one user/pw type to another\"\"\"\n    return dict(user=user + \"_1\", password=password + \"_2\")\n\n\nclass _CCred1(CompositeCredential):\n    \"\"\"A Simple composite credential which will do some entries transformation\n    \"\"\"\n    _CREDENTIAL_CLASSES = (UserPassword, UserPassword)\n    _CREDENTIAL_ADAPTERS = (_cred1_adapter,)\n\n\n@with_testsui(responses=['user1', 'password1',\n                         'user2', 'password2'])\ndef test_composite_credential1():\n    # basic test of composite credential\n    keyring = MemoryKeyring()\n    cred = _CCred1(\"name\", keyring=keyring)\n    # When queried, does the chain\n    assert_equal(cred(), {'user': 'user1_1', 'password': 'password1_2'})\n    # But the \"Front\" credential is exposed to the user\n    assert_equal(cred.get('user'), 'user1')\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_raises(ValueError, cred.get, 'unknown_field')\n    assert_equal(cred.get('password'), 'password1')\n    assert_equal(keyring.get('name', 'password'), 'password1')\n    # ATM composite credential stores \"derived\" ones unconditionally in the\n    # keyring as well\n    assert_equal(keyring.get('name:1', 'user'), 'user1_1')\n    assert_equal(keyring.get('name:1', 'password'), 'password1_2')\n\n    # and now enter new should remove \"derived\" entries\n    cred.enter_new()\n    assert_equal(keyring.get('name', 'user'), 'user2')\n    assert_equal(keyring.get('name', 'password'), 'password2')\n    assert_equal(keyring.get('name:1', 'user'), None)\n    assert_equal(keyring.get('name:1', 'password'), None)\n    # which would get reevaluated if requested\n    assert_equal(keyring.entries, {'name:1': {}, 'name': {'user': 'user2', 'password': 'password2'}})\n    assert_equal(cred(), {'user': 'user2_1', 'password': 'password2_2'})\n\n\ndef test_credentials_from_env():\n    keyring = Keyring()\n    cred = AWS_S3(\"test-s3\", keyring=keyring)\n    assert_false(cred.is_known)\n    assert_equal(cred.get('key_id'), None)\n    assert_equal(cred.get('secret_id'), None)\n\n    with patch.dict('os.environ', {'DATALAD_test_s3_key_id': '1'}):\n        assert_equal(cred.get('key_id'), '1')\n        assert_false(cred.is_known)\n        with patch.dict('os.environ', {'DATALAD_test_s3_secret_id': '2'}):\n            assert_equal(cred.get('key_id'), '1')\n            assert_equal(cred.get('secret_id'), '2')\n            assert_true(cred.is_known)\n        assert_false(cred.is_known)  # no memory of the past",
            "header": {
                "file": {
                    "path": "datalad/downloaders/tests/test_credentials.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "9e02829d9",
                "new_commit_hash": "dcb82e666",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/datalad/downloaders/tests/test_credentials.py"
            },
            "plus_file": {
                "path": "b/datalad/downloaders/tests/test_credentials.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 8,
                            "length": 14
                        },
                        "new_range": {
                            "start": 8,
                            "length": 18
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##",
                                "type": "context"
                            },
                            {
                                "content": "\"\"\"Tests for credentials\"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "from mock import patch",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "from datalad.tests.utils import with_testsui",
                                "type": "context"
                            },
                            {
                                "content": "from datalad.tests.utils import assert_equal",
                                "type": "context"
                            },
                            {
                                "content": "from datalad.tests.utils import assert_true, assert_false",
                                "type": "context"
                            },
                            {
                                "content": "from datalad.tests.utils import assert_raises",
                                "type": "context"
                            },
                            {
                                "content": "from datalad.tests.utils import SkipTest",
                                "type": "context"
                            },
                            {
                                "content": "from datalad.support.keyring_ import MemoryKeyring",
                                "type": "context"
                            },
                            {
                                "content": "from datalad.support.keyring_ import Keyring",
                                "type": "added"
                            },
                            {
                                "content": "from ..credentials import UserPassword",
                                "type": "context"
                            },
                            {
                                "content": "from ..credentials import CompositeCredential",
                                "type": "context"
                            },
                            {
                                "content": "from ..credentials import AWS_S3",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "@with_testsui(responses=['user1', 'password1'])",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "datalad/downloaders/tests/test_credentials.py",
                            "type": "statement",
                            "name": "",
                            "content": "from mock import patch",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 11,
                            "end_lineno": 11,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/downloaders/tests/test_credentials.py",
                            "type": "statement",
                            "name": "",
                            "content": "from datalad.support.keyring_ import Keyring",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 19,
                            "end_lineno": 19,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/downloaders/tests/test_credentials.py",
                            "type": "statement",
                            "name": "",
                            "content": "from ..credentials import AWS_S3",
                            "ast_type_str": "ImportFrom",
                            "start_lineno": 22,
                            "end_lineno": 22,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 91,
                            "length": 3
                        },
                        "new_range": {
                            "start": 95,
                            "length": 20
                        },
                        "section": "def test_composite_credential1():"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    # which would get reevaluated if requested",
                                "type": "context"
                            },
                            {
                                "content": "    assert_equal(keyring.entries, {'name:1': {}, 'name': {'user': 'user2', 'password': 'password2'}})",
                                "type": "context"
                            },
                            {
                                "content": "    assert_equal(cred(), {'user': 'user2_1', 'password': 'password2_2'})",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "def test_credentials_from_env():",
                                "type": "added"
                            },
                            {
                                "content": "    keyring = Keyring()",
                                "type": "added"
                            },
                            {
                                "content": "    cred = AWS_S3(\"test-s3\", keyring=keyring)",
                                "type": "added"
                            },
                            {
                                "content": "    assert_false(cred.is_known)",
                                "type": "added"
                            },
                            {
                                "content": "    assert_equal(cred.get('key_id'), None)",
                                "type": "added"
                            },
                            {
                                "content": "    assert_equal(cred.get('secret_id'), None)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    with patch.dict('os.environ', {'DATALAD_test_s3_key_id': '1'}):",
                                "type": "added"
                            },
                            {
                                "content": "        assert_equal(cred.get('key_id'), '1')",
                                "type": "added"
                            },
                            {
                                "content": "        assert_false(cred.is_known)",
                                "type": "added"
                            },
                            {
                                "content": "        with patch.dict('os.environ', {'DATALAD_test_s3_secret_id': '2'}):",
                                "type": "added"
                            },
                            {
                                "content": "            assert_equal(cred.get('key_id'), '1')",
                                "type": "added"
                            },
                            {
                                "content": "            assert_equal(cred.get('secret_id'), '2')",
                                "type": "added"
                            },
                            {
                                "content": "            assert_true(cred.is_known)",
                                "type": "added"
                            },
                            {
                                "content": "        assert_false(cred.is_known)  # no memory of the past",
                                "type": "added"
                            },
                            {
                                "content": "No newline at end of file",
                                "type": "note"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "datalad/downloaders/tests/test_credentials.py",
                            "type": "function",
                            "name": "test_credentials_from_env",
                            "content": "def test_credentials_from_env():\n    keyring = Keyring()\n    cred = AWS_S3(\"test-s3\", keyring=keyring)\n    assert_false(cred.is_known)\n    assert_equal(cred.get('key_id'), None)\n    assert_equal(cred.get('secret_id'), None)\n\n    with patch.dict('os.environ', {'DATALAD_test_s3_key_id': '1'}):\n        assert_equal(cred.get('key_id'), '1')\n        assert_false(cred.is_known)\n        with patch.dict('os.environ', {'DATALAD_test_s3_secret_id': '2'}):\n            assert_equal(cred.get('key_id'), '1')\n            assert_equal(cred.get('secret_id'), '2')\n            assert_true(cred.is_known)\n        assert_false(cred.is_known)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 100,
                            "end_lineno": 114,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Adapters and decorators for keyrings\n\"\"\"\n\n\nclass Keyring(object):\n    \"\"\"Adapter to keyring module\n\n    It also delays import of keyring which takes 300ms I guess due to all plugins etc\n    \"\"\"\n    def __init__(self):\n        self.__keyring = None\n\n    @property\n    def _keyring(self):\n        if self.__keyring is None:\n            # Setup logging for keyring if we are debugging, althought keyring's logging\n            # is quite scarce ATM\n            from .. import lgr\n            import logging\n            lgr_level = lgr.getEffectiveLevel()\n            if lgr_level < logging.DEBUG:\n                keyring_lgr = logging.getLogger('keyring')\n                keyring_lgr.setLevel(lgr_level)\n                keyring_lgr.handlers = lgr.handlers\n            lgr.debug(\"Importing keyring\")\n            import keyring\n            self.__keyring = keyring\n\n        return self.__keyring\n\n    @classmethod\n    def _get_service_name(cls, name):\n        return \"datalad-%s\" % str(name)\n\n    # proxy few methods of interest explicitly, to be rebound to the module's\n    def get(self, name, field):\n        return self._keyring.get_password(self._get_service_name(name), field)\n\n    def set(self, name, field, value):\n        return self._keyring.set_password(self._get_service_name(name), field, value)\n\n    def delete(self, name, field=None):\n        if field is None:\n            raise NotImplementedError(\"Deletion of all fields associated with a name\")\n        return self._keyring.delete_password(self._get_service_name(name), field)\n\n\nclass MemoryKeyring(object):\n    \"\"\"A simple keyring which just stores provided info in memory\n\n    Primarily for testing\n    \"\"\"\n\n    def __init__(self):\n        self.entries = {}\n\n    def get(self, name, field):\n        \"\"\"Get password from the specified service.\n        \"\"\"\n        # to mimic behavior of keyring module\n        return self.entries[name][field] \\\n            if name in self.entries and field in self.entries[name] \\\n            else None\n\n    def set(self, name, field, value):\n        \"\"\"Set password for the user in the specified service.\n        \"\"\"\n        self.entries.setdefault(name, {}).update({field: value})\n\n    def delete(self, name, field=None):\n        \"\"\"Delete password from the specified service.\n        \"\"\"\n        if name in self.entries:\n            if field:\n                self.entries[name].pop(field)\n            else:\n                # TODO: might be implemented by some super class if .keys() of some kind provided\n                self.entries.pop(name)\n        else:\n            raise KeyError(\"No entries associated with %s\" % name)\n\n\nkeyring = Keyring()\n",
            "new_file_content": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Adapters and decorators for keyrings\n\"\"\"\n\nimport os\n\n\nclass Keyring(object):\n    \"\"\"Adapter to keyring module\n\n    It also delays import of keyring which takes 300ms I guess due to all plugins etc\n    \"\"\"\n    def __init__(self):\n        self.__keyring = None\n\n    @property\n    def _keyring(self):\n        if self.__keyring is None:\n            # Setup logging for keyring if we are debugging, althought keyring's logging\n            # is quite scarce ATM\n            from .. import lgr\n            import logging\n            lgr_level = lgr.getEffectiveLevel()\n            if lgr_level < logging.DEBUG:\n                keyring_lgr = logging.getLogger('keyring')\n                keyring_lgr.setLevel(lgr_level)\n                keyring_lgr.handlers = lgr.handlers\n            lgr.debug(\"Importing keyring\")\n            import keyring\n            self.__keyring = keyring\n\n        return self.__keyring\n\n    @classmethod\n    def _get_service_name(cls, name):\n        return \"datalad-%s\" % str(name)\n\n    # proxy few methods of interest explicitly, to be rebound to the module's\n    def get(self, name, field):\n        # consult environment, might be provided there\n        val = self._keyring.get_password(self._get_service_name(name), field)\n        if val is None:\n            val = os.environ.get(('DATALAD_%s_%s' % (name, field)).replace('-', '_'), None)\n        return val\n\n    def set(self, name, field, value):\n        return self._keyring.set_password(self._get_service_name(name), field, value)\n\n    def delete(self, name, field=None):\n        if field is None:\n            raise NotImplementedError(\"Deletion of all fields associated with a name\")\n        return self._keyring.delete_password(self._get_service_name(name), field)\n\n\nclass MemoryKeyring(object):\n    \"\"\"A simple keyring which just stores provided info in memory\n\n    Primarily for testing\n    \"\"\"\n\n    def __init__(self):\n        self.entries = {}\n\n    def get(self, name, field):\n        \"\"\"Get password from the specified service.\n        \"\"\"\n        # to mimic behavior of keyring module\n        return self.entries[name][field] \\\n            if name in self.entries and field in self.entries[name] \\\n            else None\n\n    def set(self, name, field, value):\n        \"\"\"Set password for the user in the specified service.\n        \"\"\"\n        self.entries.setdefault(name, {}).update({field: value})\n\n    def delete(self, name, field=None):\n        \"\"\"Delete password from the specified service.\n        \"\"\"\n        if name in self.entries:\n            if field:\n                self.entries[name].pop(field)\n            else:\n                # TODO: might be implemented by some super class if .keys() of some kind provided\n                self.entries.pop(name)\n        else:\n            raise KeyError(\"No entries associated with %s\" % name)\n\n\nkeyring = Keyring()\n",
            "header": {
                "file": {
                    "path": "datalad/support/keyring_.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "e4ec4861b",
                "new_commit_hash": "69d6abe16",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/datalad/support/keyring_.py"
            },
            "plus_file": {
                "path": "b/datalad/support/keyring_.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 9,
                            "length": 6
                        },
                        "new_range": {
                            "start": 9,
                            "length": 8
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "\"\"\"Adapters and decorators for keyrings",
                                "type": "context"
                            },
                            {
                                "content": "\"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "import os",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "class Keyring(object):",
                                "type": "context"
                            },
                            {
                                "content": "    \"\"\"Adapter to keyring module",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "datalad/support/keyring_.py",
                            "type": "import",
                            "name": "os",
                            "content": "import os",
                            "ast_type_str": "Import",
                            "start_lineno": 12,
                            "end_lineno": 12,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 42,
                            "length": 7
                        },
                        "new_range": {
                            "start": 44,
                            "length": 11
                        },
                        "section": "class Keyring(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    # proxy few methods of interest explicitly, to be rebound to the module's",
                                "type": "context"
                            },
                            {
                                "content": "    def get(self, name, field):",
                                "type": "context"
                            },
                            {
                                "content": "        return self._keyring.get_password(self._get_service_name(name), field)",
                                "type": "deleted"
                            },
                            {
                                "content": "        # consult environment, might be provided there",
                                "type": "added"
                            },
                            {
                                "content": "        val = self._keyring.get_password(self._get_service_name(name), field)",
                                "type": "added"
                            },
                            {
                                "content": "        if val is None:",
                                "type": "added"
                            },
                            {
                                "content": "            val = os.environ.get(('DATALAD_%s_%s' % (name, field)).replace('-', '_'), None)",
                                "type": "added"
                            },
                            {
                                "content": "        return val",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def set(self, name, field, value):",
                                "type": "context"
                            },
                            {
                                "content": "        return self._keyring.set_password(self._get_service_name(name), field, value)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "datalad/support/keyring_.py",
                            "type": "class",
                            "name": "Keyring",
                            "content": "class Keyring(object):\n    \"\"\"Adapter to keyring module\n\n    It also delays import of keyring which takes 300ms I guess due to all plugins etc\n    \"\"\"\n    def __init__(self):\n        self.__keyring = None\n\n    @property\n    def _keyring(self):\n        if self.__keyring is None:\n            # Setup logging for keyring if we are debugging, althought keyring's logging\n            # is quite scarce ATM\n            from .. import lgr\n            import logging\n            lgr_level = lgr.getEffectiveLevel()\n            if lgr_level < logging.DEBUG:\n                keyring_lgr = logging.getLogger('keyring')\n                keyring_lgr.setLevel(lgr_level)\n                keyring_lgr.handlers = lgr.handlers\n            lgr.debug(\"Importing keyring\")\n            import keyring\n            self.__keyring = keyring\n\n        return self.__keyring\n\n    @classmethod\n    def _get_service_name(cls, name):\n        return \"datalad-%s\" % str(name)\n\n    # proxy few methods of interest explicitly, to be rebound to the module's\n    def get(self, name, field):\n        return self._keyring.get_password(self._get_service_name(name), field)\n\n    def set(self, name, field, value):\n        return self._keyring.set_password(self._get_service_name(name), field, value)\n\n    def delete(self, name, field=None):\n        if field is None:\n            raise NotImplementedError(\"Deletion of all fields associated with a name\")\n        return self._keyring.delete_password(self._get_service_name(name), field)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 13,
                            "end_lineno": 53,
                            "parent": null
                        },
                        {
                            "file_name": "datalad/support/keyring_.py",
                            "type": "method",
                            "name": "Keyring.get",
                            "content": "class Keyring(object):\n    \"\"\"Adapter to keyring module\n\n    It also delays import of keyring which takes 300ms I guess due to all plugins etc\n    \"\"\"\n    def __init__(self):\n        self.__keyring = None\n\n    @property\n    def _keyring(self):\n        if self.__keyring is None:\n            # Setup logging for keyring if we are debugging, althought keyring's logging\n            # is quite scarce ATM\n            from .. import lgr\n            import logging\n            lgr_level = lgr.getEffectiveLevel()\n            if lgr_level < logging.DEBUG:\n                keyring_lgr = logging.getLogger('keyring')\n                keyring_lgr.setLevel(lgr_level)\n                keyring_lgr.handlers = lgr.handlers\n            lgr.debug(\"Importing keyring\")\n            import keyring\n            self.__keyring = keyring\n\n        return self.__keyring\n\n    @classmethod\n    def _get_service_name(cls, name):\n        return \"datalad-%s\" % str(name)\n\n    # proxy few methods of interest explicitly, to be rebound to the module's\n    def get(self, name, field):\n        return self._keyring.get_password(self._get_service_name(name), field)\n\n    def set(self, name, field, value):\n        return self._keyring.set_password(self._get_service_name(name), field, value)\n\n    def delete(self, name, field=None):\n        if field is None:\n            raise NotImplementedError(\"Deletion of all fields associated with a name\")\n        return self._keyring.delete_password(self._get_service_name(name), field)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 44,
                            "end_lineno": 45,
                            "parent": {
                                "file_name": "datalad/support/keyring_.py",
                                "type": "class",
                                "name": "Keyring",
                                "content": "class Keyring(object):\n    \"\"\"Adapter to keyring module\n\n    It also delays import of keyring which takes 300ms I guess due to all plugins etc\n    \"\"\"\n    def __init__(self):\n        self.__keyring = None\n\n    @property\n    def _keyring(self):\n        if self.__keyring is None:\n            # Setup logging for keyring if we are debugging, althought keyring's logging\n            # is quite scarce ATM\n            from .. import lgr\n            import logging\n            lgr_level = lgr.getEffectiveLevel()\n            if lgr_level < logging.DEBUG:\n                keyring_lgr = logging.getLogger('keyring')\n                keyring_lgr.setLevel(lgr_level)\n                keyring_lgr.handlers = lgr.handlers\n            lgr.debug(\"Importing keyring\")\n            import keyring\n            self.__keyring = keyring\n\n        return self.__keyring\n\n    @classmethod\n    def _get_service_name(cls, name):\n        return \"datalad-%s\" % str(name)\n\n    # proxy few methods of interest explicitly, to be rebound to the module's\n    def get(self, name, field):\n        return self._keyring.get_password(self._get_service_name(name), field)\n\n    def set(self, name, field, value):\n        return self._keyring.set_password(self._get_service_name(name), field, value)\n\n    def delete(self, name, field=None):\n        if field is None:\n            raise NotImplementedError(\"Deletion of all fields associated with a name\")\n        return self._keyring.delete_password(self._get_service_name(name), field)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 13,
                                "end_lineno": 53,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "d644c75e89f8b2daadbfedfc995ffcf6c2a0341b^",
    "new_commit_hash": "d644c75e89f8b2daadbfedfc995ffcf6c2a0341b",
    "commit_message": "ENH: allow credentials to be provided via env vars",
    "commit_date": "2016-09-01T20:40:52-04:00",
    "metadata": {}
}
{
    "repo_name": "datalad",
    "new_commit_hash": "d644c75e89f8b2daadbfedfc995ffcf6c2a0341b",
    "test_file_codes": [
        "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Tests for credentials\"\"\"\n\nfrom mock import patch\n\nfrom datalad.tests.utils import with_testsui\nfrom datalad.tests.utils import assert_equal\nfrom datalad.tests.utils import assert_true, assert_false\nfrom datalad.tests.utils import assert_raises\nfrom datalad.tests.utils import SkipTest\nfrom datalad.support.keyring_ import MemoryKeyring\nfrom datalad.support.keyring_ import Keyring\nfrom datalad.downloaders.credentials import UserPassword\nfrom datalad.downloaders.credentials import CompositeCredential\nfrom datalad.downloaders.credentials import AWS_S3\n\n\n@with_testsui(responses=['user1', 'password1'])\ndef test_cred1_enter_new():\n    keyring = MemoryKeyring()\n    cred = UserPassword(\"name\", keyring=keyring)\n    assert_false(cred.is_known)\n    assert_equal(cred.enter_new(), None)\n    assert_true(cred.is_known)\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_equal(keyring.get('name', 'password'), 'password1')\n    keyring.delete('name')\n    assert_raises(KeyError, keyring.delete, 'name', 'user')\n    assert_raises(KeyError, keyring.delete, 'name')\n    assert_equal(keyring.get('name', 'user'), None)\n\n\n@with_testsui(responses=['password1'])\ndef test_cred1_call():\n    keyring = MemoryKeyring()\n    cred = UserPassword(\"name\", keyring=keyring)\n    # we will set the name but not the password, expecting UI\n    # requesting it\n    assert_equal(keyring.set('name', 'user', 'user1'), None)\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_equal(cred(), {'user': 'user1', 'password': 'password1'})\n    assert_equal(keyring.get('name', 'password'), 'password1')\n\n\ndef test_keyring():\n    # mock out keyring methods and test that we are providing correct values\n    # with 'datalad-' prefix\n    raise SkipTest(\"provide tests for Keyring which interfaces keyring module\")\n\n\ndef _cred1_adapter(user=None, password=None):\n    \"\"\"Just a sample adapter from one user/pw type to another\"\"\"\n    return dict(user=user + \"_1\", password=password + \"_2\")\n\n\nclass _CCred1(CompositeCredential):\n    \"\"\"A Simple composite credential which will do some entries transformation\n    \"\"\"\n    _CREDENTIAL_CLASSES = (UserPassword, UserPassword)\n    _CREDENTIAL_ADAPTERS = (_cred1_adapter,)\n\n\n@with_testsui(responses=['user1', 'password1',\n                         'user2', 'password2'])\ndef test_composite_credential1():\n    # basic test of composite credential\n    keyring = MemoryKeyring()\n    cred = _CCred1(\"name\", keyring=keyring)\n    # When queried, does the chain\n    assert_equal(cred(), {'user': 'user1_1', 'password': 'password1_2'})\n    # But the \"Front\" credential is exposed to the user\n    assert_equal(cred.get('user'), 'user1')\n    assert_equal(keyring.get('name', 'user'), 'user1')\n    assert_raises(ValueError, cred.get, 'unknown_field')\n    assert_equal(cred.get('password'), 'password1')\n    assert_equal(keyring.get('name', 'password'), 'password1')\n    # ATM composite credential stores \"derived\" ones unconditionally in the\n    # keyring as well\n    assert_equal(keyring.get('name:1', 'user'), 'user1_1')\n    assert_equal(keyring.get('name:1', 'password'), 'password1_2')\n\n    # and now enter new should remove \"derived\" entries\n    cred.enter_new()\n    assert_equal(keyring.get('name', 'user'), 'user2')\n    assert_equal(keyring.get('name', 'password'), 'password2')\n    assert_equal(keyring.get('name:1', 'user'), None)\n    assert_equal(keyring.get('name:1', 'password'), None)\n    # which would get reevaluated if requested\n    assert_equal(keyring.entries, {'name:1': {}, 'name': {'user': 'user2', 'password': 'password2'}})\n    assert_equal(cred(), {'user': 'user2_1', 'password': 'password2_2'})\n\n\ndef test_credentials_from_env():\n    keyring = Keyring()\n    cred = AWS_S3(\"test-s3\", keyring=keyring)\n    assert_false(cred.is_known)\n    assert_equal(cred.get('key_id'), None)\n    assert_equal(cred.get('secret_id'), None)\n\n    with patch.dict('os.environ', {'DATALAD_test_s3_key_id': '1'}):\n        assert_equal(cred.get('key_id'), '1')\n        assert_false(cred.is_known)\n        with patch.dict('os.environ', {'DATALAD_test_s3_secret_id': '2'}):\n            assert_equal(cred.get('key_id'), '1')\n            assert_equal(cred.get('secret_id'), '2')\n            assert_true(cred.is_known)\n        assert_false(cred.is_known)  # no memory of the past",
        "import pytest\nimport tempfile\nimport os\n\n\n@pytest.fixture\ndef path():\n    with tempfile.TemporaryDirectory() as tmpdir:\n        yield tmpdir\n\n\n@pytest.fixture(autouse=True)\ndef setup_git_config():\n    with tempfile.TemporaryDirectory() as home:\n        old_home = os.environ.get(\"HOME\")\n        os.environ[\"HOME\"] = home\n        os.system('git config --global user.name \"DataLad Tester\"')\n        os.system('git config --global user.email \"test@example.com\"')\n        yield\n        if old_home:\n            os.environ[\"HOME\"] = old_home\n"
    ],
    "test_file_names": [
        "test_1.py",
        "conftest.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Datalad installation attempts...\nVerifying installation...\n❌ Verification failed\nPython 3.9 installation failed, trying Python 3.7...\nVerifying installation...\nDatalad version: 0.2.3\n✅ Installation successful!\nSuccessfully installed Datalad using Python 3.7\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 25 packages in 108ms\nInstalled 25 packages in 4.24s\n + coverage==7.6.10\n + docopt==0.6.2\n + exceptiongroup==1.2.2\n + grabbit==0.2.6\n + importlib-resources==6.4.5\n + iniconfig==2.0.0\n + nibabel==5.3.2\n + num2words==0.5.14\n + numpy==2.0.2\n + packaging==24.2\n + pandas==2.2.3\n + patsy==1.0.1\n + pluggy==1.5.0\n + pybids==0.6.5\n + pytest==8.3.4\n + pytest-cov==6.0.0\n + python-dateutil==2.9.0.post0\n + pytz==2024.2\n + scipy==1.13.1\n + setuptools==75.6.0\n + six==1.17.0\n + tomli==2.2.1\n + typing-extensions==4.12.2\n + tzdata==2024.2\n + zipp==3.21.0\nerror: The build backend returned an error\n  Caused by: Call to `setuptools.build_meta:__legacy__.build_editable` failed (exit status: 1)\n\n[stderr]\nTraceback (most recent call last):\n  File \"<string>\", line 14, in <module>\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpHhokFq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 483, in get_requires_for_build_editable\n    return self.get_requires_for_build_wheel(config_settings)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpHhokFq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 334, in get_requires_for_build_wheel\n    return self._get_build_requires(config_settings, requirements=[])\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpHhokFq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 304, in _get_build_requires\n    self.run_setup()\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpHhokFq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 522, in run_setup\n    super().run_setup(setup_script=setup_script)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpHhokFq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 320, in run_setup\n    exec(code, locals())\n  File \"<string>\", line 35, in <module>\nAttributeError: module 'platform' has no attribute 'dist'\n\nhint: This usually indicates a problem with the package or the build environment.\nerror: The build backend returned an error\n  Caused by: Call to `setuptools.build_meta:__legacy__.build_editable` failed (exit status: 1)\n\n[stderr]\nTraceback (most recent call last):\n  File \"<string>\", line 14, in <module>\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpxFORVq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 483, in get_requires_for_build_editable\n    return self.get_requires_for_build_wheel(config_settings)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpxFORVq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 334, in get_requires_for_build_wheel\n    return self._get_build_requires(config_settings, requirements=[])\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpxFORVq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 304, in _get_build_requires\n    self.run_setup()\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpxFORVq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 522, in run_setup\n    super().run_setup(setup_script=setup_script)\n  File \"/home/gcpuser/.cache/uv/builds-v0/.tmpxFORVq/lib/python3.9/site-packages/setuptools/build_meta.py\", line 320, in run_setup\n    exec(code, locals())\n  File \"<string>\", line 35, in <module>\nAttributeError: module 'platform' has no attribute 'dist'\n\nhint: This usually indicates a problem with the package or the build environment.\nTraceback (most recent call last):\n  File \"<string>\", line 1, in <module>\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_d644c75e89f8b2daadbfedfc995ffcf6c2a0341b/datalad/__init__.py\", line 17, in <module>\n    from .config import ConfigManager\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_d644c75e89f8b2daadbfedfc995ffcf6c2a0341b/datalad/config.py\", line 17, in <module>\n    from appdirs import AppDirs\nModuleNotFoundError: No module named 'appdirs'\nUsing CPython 3.7.9\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 26 packages in 342ms\nInstalled 26 packages in 7.24s\n + bids==0.0\n + coverage==7.2.7\n + docopt==0.6.2\n + exceptiongroup==1.2.2\n + fasteners==0.19\n + grabbit==0.2.6\n + importlib-metadata==6.7.0\n + iniconfig==2.0.0\n + nibabel==4.0.2\n + num2words==0.5.14\n + numpy==1.21.6\n + packaging==24.0\n + pandas==1.3.5\n + patsy==1.0.1\n + pluggy==1.2.0\n + pybids==0.6.5\n + pytest==7.4.4\n + pytest-cov==4.1.0\n + python-dateutil==2.9.0.post0\n + pytz==2024.2\n + scipy==1.7.3\n + setuptools==68.0.0\n + six==1.17.0\n + tomli==2.0.1\n + typing-extensions==4.7.1\n + zipp==3.15.0\nResolved 68 packages in 3.65s\nPrepared 1 package in 1.23s\nInstalled 62 packages in 77ms\n + appdirs==1.4.4\n + attrs==24.2.0\n + automat==22.10.0\n + beautifulsoup4==4.12.3\n + boto==2.49.0\n + certifi==2024.12.14\n + cffi==1.15.1\n + charset-normalizer==3.4.1\n + constantly==15.1.0\n + cryptography==44.0.0\n + cssselect==1.2.0\n + datalad==0.2.3 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_d644c75e89f8b2daadbfedfc995ffcf6c2a0341b)\n + filelock==3.12.2\n + gitdb==4.0.12\n + gitpython==3.1.44\n + httpretty==1.1.4\n + humanize==4.6.0\n + hyperlink==21.0.0\n + idna==3.10\n + importlib-resources==5.12.0\n + incremental==22.10.0\n + iso8601==2.1.0\n + itemadapter==0.8.0\n + itemloaders==1.1.0\n + jaraco-classes==3.2.3\n + jeepney==0.8.0\n + jmespath==1.0.1\n + keyring==24.1.1\n + keyrings-alt==4.2.0\n + lxml==5.3.0\n + mock==5.1.0\n + more-itertools==9.1.0\n + msgpack-python==0.5.6\n + multidict==6.0.5\n + nose==1.3.7\n + parsel==1.8.1\n + patool==1.12\n + protego==0.3.0\n + pyasn1==0.5.1\n + pyasn1-modules==0.3.0\n + pycparser==2.21\n + pydispatcher==2.0.7\n + pyopenssl==24.3.0\n + pyyaml==6.0.1\n + queuelib==1.6.2\n + requests==2.31.0\n + requests-file==2.1.0\n + requests-ftp==0.3.1\n + scrapy==2.9.0\n + secretstorage==3.3.3\n + service-identity==21.1.0\n + smmap==5.0.2\n + soupsieve==2.4.1\n + tldextract==4.0.0\n + tqdm==4.67.1\n + twisted==23.8.0\n + urllib3==2.0.7\n + vcrpy==4.3.0\n + w3lib==2.1.2\n + wrapt==1.16.0\n + yarl==1.9.4\n + zope-interface==6.4.post2\nAudited 1 package in 5ms\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_d644c75e89f8b2daadbfedfc995ffcf6c2a0341b\nplugins: cov-4.1.0\ncollected 5 items\n\nr2e_tests/test_1.py ..s..                                                [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_cred1_enter_new\nPASSED r2e_tests/test_1.py::test_cred1_call\nPASSED r2e_tests/test_1.py::test_composite_credential1\nPASSED r2e_tests/test_1.py::test_credentials_from_env\nSKIPPED [1] .venv/lib/python3.7/site-packages/_pytest/unittest.py:371: provide tests for Keyring which interfaces keyring module\n========================= 4 passed, 1 skipped in 2.01s =========================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.7.9, pytest-7.4.4, pluggy-1.2.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/datalad_d644c75e89f8b2daadbfedfc995ffcf6c2a0341b\nplugins: cov-4.1.0\ncollected 5 items\n\nr2e_tests/test_1.py ..s.F                                                [100%]\n\n=================================== FAILURES ===================================\n__________________________ test_credentials_from_env ___________________________\n\n    def test_credentials_from_env():\n        keyring = Keyring()\n        cred = AWS_S3(\"test-s3\", keyring=keyring)\n        assert_false(cred.is_known)\n        assert_equal(cred.get('key_id'), None)\n        assert_equal(cred.get('secret_id'), None)\n    \n        with patch.dict('os.environ', {'DATALAD_test_s3_key_id': '1'}):\n>           assert_equal(cred.get('key_id'), '1')\n\nr2e_tests/test_1.py:108: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/unittest/case.py:852: in assertEqual\n    assertion_func(first, second, msg=msg)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <nose.tools.trivial.Dummy testMethod=nop>, first = None, second = '1'\nmsg = \"None != '1'\"\n\n    def _baseAssertEqual(self, first, second, msg=None):\n        \"\"\"The default assertEqual implementation, not type specific.\"\"\"\n        if not first == second:\n            standardMsg = '%s != %s' % _common_shorten_repr(first, second)\n            msg = self._formatMessage(msg, standardMsg)\n>           raise self.failureException(msg)\nE           AssertionError: None != '1'\n\n../../../../.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib/python3.7/unittest/case.py:845: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_cred1_enter_new\nPASSED r2e_tests/test_1.py::test_cred1_call\nPASSED r2e_tests/test_1.py::test_composite_credential1\nSKIPPED [1] .venv/lib/python3.7/site-packages/_pytest/unittest.py:371: provide tests for Keyring which interfaces keyring module\nFAILED r2e_tests/test_1.py::test_credentials_from_env - AssertionError: None ...\n==================== 1 failed, 3 passed, 1 skipped in 0.64s ====================\n",
    "old_commit_res_stderr": ""
}
datalad/downloaders/tests/test_credentials.py datalad/support/keyring_.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Unable to Provide AWS_S3 Credentials via Environment Variables

**Description:**
When attempting to supply AWS_S3 credentials through environment variables, the system fails to recognize them. This prevents the retrieval of credentials as expected.

**Example Buggy Code:**
```python
keyring = Keyring()
cred = AWS_S3("test-s3", keyring=keyring)
print(cred.get('key_id'))  # Expected to retrieve from environment variable
```

**Expected Behavior:**
The `get('key_id')` method should retrieve the `key_id` from the specified environment variable, returning the value set in `os.environ`.

**Actual Behavior:**
The `get('key_id')` method returns `None`, indicating that the environment variable is not being accessed or recognized.
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### datalad/support/keyring_.py
# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
# ex: set sts=4 ts=4 sw=4 noet:
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
#   See COPYING file distributed along with the datalad package for the
#   copyright and license terms.
#
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""Adapters and decorators for keyrings
"""


class Keyring(object):
    """Adapter to keyring module

    It also delays import of keyring which takes 300ms I guess due to all plugins etc
    """
    def __init__(self):
        self.__keyring = None

    @property
    def _keyring(self):
        if self.__keyring is None:
            # Setup logging for keyring if we are debugging, althought keyring's logging
            # is quite scarce ATM
            from .. import lgr
            import logging
            lgr_level = lgr.getEffectiveLevel()
            if lgr_level < logging.DEBUG:
                keyring_lgr = logging.getLogger('keyring')
                keyring_lgr.setLevel(lgr_level)
                keyring_lgr.handlers = lgr.handlers
            lgr.debug("Importing keyring")
            import keyring
            self.__keyring = keyring

        return self.__keyring

    @classmethod
    def _get_service_name(cls, name):
        return "datalad-%s" % str(name)

    # proxy few methods of interest explicitly, to be rebound to the module's
    def get(self, name, field):
        return self._keyring.get_password(self._get_service_name(name), field)

    def set(self, name, field, value):
        return self._keyring.set_password(self._get_service_name(name), field, value)

    def delete(self, name, field=None):
        if field is None:
            raise NotImplementedError("Deletion of all fields associated with a name")
        return self._keyring.delete_password(self._get_service_name(name), field)


class MemoryKeyring(object):
    """A simple keyring which just stores provided info in memory

    Primarily for testing
    """

    def __init__(self):
        self.entries = {}

    def get(self, name, field):
        """Get password from the specified service.
        """
        # to mimic behavior of keyring module
        return self.entries[name][field] \
            if name in self.entries and field in self.entries[name] \
            else None

    def set(self, name, field, value):
        """Set password for the user in the specified service.
        """
        self.entries.setdefault(name, {}).update({field: value})

    def delete(self, name, field=None):
        """Delete password from the specified service.
        """
        if name in self.entries:
            if field:
                self.entries[name].pop(field)
            else:
                # TODO: might be implemented by some super class if .keys() of some kind provided
                self.entries.pop(name)
        else:
            raise KeyError("No entries associated with %s" % name)


keyring = Keyring()

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Unable to Provide AWS_S3 Credentials via Environment Variables

**Description:**
When attempting to supply AWS_S3 credentials through environment variables, the system fails to recognize them. This prevents the retrieval of credentials as expected.

**Example Buggy Code:**
```python
keyring = Keyring()
cred = AWS_S3("test-s3", keyring=keyring)
print(cred.get('key_id'))  # Expected to retrieve from environment variable
```

**Expected Behavior:**
The `get('key_id')` method should retrieve the `key_id` from the specified environment variable, returning the value set in `os.environ`.

**Actual Behavior:**
The `get('key_id')` method returns `None`, indicating that the environment variable is not being accessed or recognized.
[/ISSUE]
{
    "test_cred1_enter_new": "PASSED",
    "test_cred1_call": "PASSED",
    "test_composite_credential1": "PASSED",
    "test_credentials_from_env": "PASSED"
}
diff --git a/datalad/support/keyring_.py b/datalad/support/keyring_.py
index e4ec4861b..69d6abe16 100644
--- a/datalad/support/keyring_.py
+++ b/datalad/support/keyring_.py
@@ -9,6 +9,8 @@
 """Adapters and decorators for keyrings
 """
 
+import os
+
 
 class Keyring(object):
     """Adapter to keyring module
@@ -42,7 +44,11 @@ class Keyring(object):
 
     # proxy few methods of interest explicitly, to be rebound to the module's
     def get(self, name, field):
-        return self._keyring.get_password(self._get_service_name(name), field)
+        # consult environment, might be provided there
+        val = self._keyring.get_password(self._get_service_name(name), field)
+        if val is None:
+            val = os.environ.get(('DATALAD_%s_%s' % (name, field)).replace('-', '_'), None)
+        return val
 
     def set(self, name, field, value):
         return self._keyring.set_password(self._get_service_name(name), field, value)
 

{"datalad/support/keyring_.py": "# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-\n# ex: set sts=4 ts=4 sw=4 noet:\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n#\n#   See COPYING file distributed along with the datalad package for the\n#   copyright and license terms.\n#\n# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##\n\"\"\"Adapters and decorators for keyrings\n\"\"\"\n\n\nclass Keyring(object):\n    \"\"\"Adapter to keyring module\n\n    It also delays import of keyring which takes 300ms I guess due to all plugins etc\n    \"\"\"\n    def __init__(self):\n        self.__keyring = None\n\n    @property\n    def _keyring(self):\n        if self.__keyring is None:\n            # Setup logging for keyring if we are debugging, althought keyring's logging\n            # is quite scarce ATM\n            from .. import lgr\n            import logging\n            lgr_level = lgr.getEffectiveLevel()\n            if lgr_level < logging.DEBUG:\n                keyring_lgr = logging.getLogger('keyring')\n                keyring_lgr.setLevel(lgr_level)\n                keyring_lgr.handlers = lgr.handlers\n            lgr.debug(\"Importing keyring\")\n            import keyring\n            self.__keyring = keyring\n\n        return self.__keyring\n\n    @classmethod\n    def _get_service_name(cls, name):\n        return \"datalad-%s\" % str(name)\n\n    # proxy few methods of interest explicitly, to be rebound to the module's\n    def get(self, name, field):\n        return self._keyring.get_password(self._get_service_name(name), field)\n\n    def set(self, name, field, value):\n        return self._keyring.set_password(self._get_service_name(name), field, value)\n\n    def delete(self, name, field=None):\n        if field is None:\n            raise NotImplementedError(\"Deletion of all fields associated with a name\")\n        return self._keyring.delete_password(self._get_service_name(name), field)\n\n\nclass MemoryKeyring(object):\n    \"\"\"A simple keyring which just stores provided info in memory\n\n    Primarily for testing\n    \"\"\"\n\n    def __init__(self):\n        self.entries = {}\n\n    def get(self, name, field):\n        \"\"\"Get password from the specified service.\n        \"\"\"\n        # to mimic behavior of keyring module\n        return self.entries[name][field] \\\n            if name in self.entries and field in self.entries[name] \\\n            else None\n\n    def set(self, name, field, value):\n        \"\"\"Set password for the user in the specified service.\n        \"\"\"\n        self.entries.setdefault(name, {}).update({field: value})\n\n    def delete(self, name, field=None):\n        \"\"\"Delete password from the specified service.\n        \"\"\"\n        if name in self.entries:\n            if field:\n                self.entries[name].pop(field)\n            else:\n                # TODO: might be implemented by some super class if .keys() of some kind provided\n                self.entries.pop(name)\n        else:\n            raise KeyError(\"No entries associated with %s\" % name)\n\n\nkeyring = Keyring()\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Unable to Provide AWS_S3 Credentials via Environment Variables

**Description:**
When attempting to supply AWS_S3 credentials through environment variables, the system fails to recognize them. This prevents the retrieval of credentials as expected.

**Example Buggy Code:**
```python
keyring = Keyring()
cred = AWS_S3("test-s3", keyring=keyring)
print(cred.get('key_id'))  # Expected to retrieve from environment variable
```

**Expected Behavior:**
The `get('key_id')` method should retrieve the `key_id` from the specified environment variable, returning the value set in `os.environ`.

**Actual Behavior:**
The `get('key_id')` method returns `None`, indicating that the environment variable is not being accessed or recognized.
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### datalad/support/keyring_.py
# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
# ex: set sts=4 ts=4 sw=4 noet:
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
#   See COPYING file distributed along with the datalad package for the
#   copyright and license terms.
#
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""Adapters and decorators for keyrings
"""


class Keyring(object):
    """Adapter to keyring module

    It also delays import of keyring which takes 300ms I guess due to all plugins etc
    """
    def __init__(self):
        self.__keyring = None

    @property
    def _keyring(self):
        if self.__keyring is None:
            # Setup logging for keyring if we are debugging, althought keyring's logging
            # is quite scarce ATM
            from .. import lgr
            import logging
            lgr_level = lgr.getEffectiveLevel()
            if lgr_level < logging.DEBUG:
                keyring_lgr = logging.getLogger('keyring')
                keyring_lgr.setLevel(lgr_level)
                keyring_lgr.handlers = lgr.handlers
            lgr.debug("Importing keyring")
            import keyring
            self.__keyring = keyring

        return self.__keyring

    @classmethod
    def _get_service_name(cls, name):
        return "datalad-%s" % str(name)

    # proxy few methods of interest explicitly, to be rebound to the module's
    def get(self, name, field):
        return self._keyring.get_password(self._get_service_name(name), field)

    def set(self, name, field, value):
        return self._keyring.set_password(self._get_service_name(name), field, value)

    def delete(self, name, field=None):
        if field is None:
            raise NotImplementedError("Deletion of all fields associated with a name")
        return self._keyring.delete_password(self._get_service_name(name), field)


class MemoryKeyring(object):
    """A simple keyring which just stores provided info in memory

    Primarily for testing
    """

    def __init__(self):
        self.entries = {}

    def get(self, name, field):
        """Get password from the specified service.
        """
        # to mimic behavior of keyring module
        return self.entries[name][field] \
            if name in self.entries and field in self.entries[name] \
            else None

    def set(self, name, field, value):
        """Set password for the user in the specified service.
        """
        self.entries.setdefault(name, {}).update({field: value})

    def delete(self, name, field=None):
        """Delete password from the specified service.
        """
        if name in self.entries:
            if field:
                self.entries[name].pop(field)
            else:
                # TODO: might be implemented by some super class if .keys() of some kind provided
                self.entries.pop(name)
        else:
            raise KeyError("No entries associated with %s" % name)


keyring = Keyring()

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user