Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jaraco/keyring
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v24.3.1
Choose a base ref
...
head repository: jaraco/keyring
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v25.0.0
Choose a head ref

Commits on Feb 12, 2024

  1. Copy the full SHA
    178d254 View commit details

Commits on Feb 18, 2024

  1. Copy the full SHA
    779219c View commit details

Commits on Mar 2, 2024

  1. Copy the full SHA
    d1c5444 View commit details
  2. Copy the full SHA
    b434f69 View commit details

Commits on Mar 12, 2024

  1. Copy the full SHA
    0bc1506 View commit details
  2. Copy the full SHA
    e7d399d View commit details
  3. Prefer map when appropriate.

    jaraco committed Mar 12, 2024
    Copy the full SHA
    4aea1b0 View commit details
  4. Copy the full SHA
    55bdd84 View commit details
  5. Allow cf_create to create integer types as well.

    jaraco committed Mar 12, 2024
    Copy the full SHA
    f3e711d View commit details

Commits on Mar 21, 2024

  1. Allow mypy on PyPy (jaraco/skeleton#111)

    pypa/setuptools#4257 shows that mypy now works with PyPy
    Avasam authored Mar 21, 2024
    Copy the full SHA
    a0d0c4b View commit details
  2. Merge https://github.com/jaraco/skeleton

    jaraco committed Mar 21, 2024
    Copy the full SHA
    e9285df View commit details

Commits on Mar 22, 2024

  1. Copy the full SHA
    1c28dee View commit details
  2. 👹 Feed the hobgoblins (delint).

    Apply ruff import sort fixes.
    jaraco committed Mar 22, 2024
    Copy the full SHA
    830cd38 View commit details
  3. Copy the full SHA
    57d3399 View commit details
  4. 👹 Feed the hobgoblins (delint).

    Ran ruff fixes for UP.
    jaraco committed Mar 22, 2024
    Copy the full SHA
    cded5d6 View commit details
  5. Consolidate adjacent strings.

    jaraco committed Mar 22, 2024
    Copy the full SHA
    cbadb25 View commit details
  6. Moved compatibility modules into a compat package.

    jaraco committed Mar 22, 2024
    Copy the full SHA
    a6db3c0 View commit details
  7. Copy the full SHA
    73c7472 View commit details
  8. Copy the full SHA
    0025c77 View commit details
  9. In platform config support, remove support for Windows XP, now 10 yea…

    …rs sunset.
    jaraco committed Mar 22, 2024
    Copy the full SHA
    1e02fde View commit details
  10. Re-use 'suppress' from jaraco.context.

    jaraco committed Mar 22, 2024
    Copy the full SHA
    8692ca2 View commit details
  11. Rely on contextlib.suppress in util.suppress_exceptions.

    jaraco committed Mar 22, 2024
    Copy the full SHA
    ca6fcd4 View commit details
  12. Apply bugbear fixes from ruff

    jaraco committed Mar 22, 2024
    Copy the full SHA
    723fc41 View commit details
  13. Copy the full SHA
    8017052 View commit details

Commits on Mar 23, 2024

  1. Remove ignore check for macOS API module now that compatible versions…

    … of Python 3.8 are in CI. Ref #547.
    jaraco committed Mar 23, 2024
    Copy the full SHA
    7881db6 View commit details
  2. 👹 Feed the hobgoblins (delint).

    Suppress B018 errors where they occur. Ref astral-sh/ruff#10536.
    jaraco committed Mar 23, 2024
    Copy the full SHA
    3a8ad34 View commit details
  3. Copy the full SHA
    0048a63 View commit details
  4. Copy the full SHA
    2838176 View commit details
  5. Copy the full SHA
    a1b5960 View commit details
  6. Copy the full SHA
    df6ebfc View commit details
  7. Copy the full SHA
    cd6df9a View commit details
  8. Copy the full SHA
    400f9dd View commit details
  9. Copy the full SHA
    1b1d172 View commit details
  10. Finalize

    jaraco committed Mar 23, 2024
    Copy the full SHA
    1eeb5c2 View commit details
10 changes: 10 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
v25.0.0
=======

Deprecations and Removals
-------------------------

- Removed check for config in XDG_DATA_HOME on Linux systems. (#99)
- In platform config support, remove support for Windows XP, now 10 years sunset.


v24.3.1
=======

23 changes: 5 additions & 18 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
import ctypes
import platform

collect_ignore = ["hook-keyring.backend.py"]

not_macOS = platform.system() != 'Darwin'

def macos_api_ignore():
"""
Starting with macOS 11, the security API becomes
non-viable except on universal2 binaries.
Ref #525.
"""

try:
ctypes.CDLL(ctypes.util.find_library('Security')).SecItemAdd
return False
except Exception:
return True


collect_ignore.extend(['keyring/backends/macOS/api.py'] * macos_api_ignore())
collect_ignore = ["hook-keyring.backend.py"] + [
'keyring/backends/macOS/api.py'
] * not_macOS
2 changes: 1 addition & 1 deletion hook-keyring.backend.py
Original file line number Diff line number Diff line change
@@ -2,6 +2,6 @@
Hook used by pyinstaller to expose hidden imports.
"""

from keyring.py312compat import metadata
from keyring.compat.py312 import metadata

hiddenimports = [ep.value for ep in metadata.entry_points(group='keyring.backends')]
8 changes: 4 additions & 4 deletions keyring/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from .core import (
set_keyring,
get_keyring,
set_password,
get_password,
delete_password,
get_credential,
get_keyring,
get_password,
set_keyring,
set_password,
)

__all__ = (
7 changes: 0 additions & 7 deletions keyring/_compat.py

This file was deleted.

43 changes: 20 additions & 23 deletions keyring/backend.py
Original file line number Diff line number Diff line change
@@ -4,23 +4,24 @@

from __future__ import annotations

import os
import abc
import copy
import logging
import operator
import copy

import os
import typing

from .py312compat import metadata
from jaraco.functools import once

from . import credentials, errors, util
from ._compat import properties
from .compat import properties
from .compat.py312 import metadata

log = logging.getLogger(__name__)


by_priority = operator.attrgetter('priority')
_limit: typing.Optional[typing.Callable[[KeyringBackend], bool]] = None
_limit: typing.Callable[[KeyringBackend], bool] | None = None


class KeyringBackendMeta(abc.ABCMeta):
@@ -67,13 +68,13 @@ def priority(self) -> float:
@properties.classproperty
def viable(cls):
with errors.ExceptionRaisedContext() as exc:
cls.priority
cls.priority # noqa: B018
return not exc

@classmethod
def get_viable_backends(
cls: typing.Type[KeyringBackend],
) -> filter[typing.Type[KeyringBackend]]:
cls: type[KeyringBackend],
) -> filter[type[KeyringBackend]]:
"""
Return all subclasses deemed viable.
"""
@@ -92,12 +93,10 @@ def name(cls) -> str:

def __str__(self) -> str:
keyring_class = type(self)
return "{}.{} (priority: {:g})".format(
keyring_class.__module__, keyring_class.__name__, keyring_class.priority
)
return f"{keyring_class.__module__}.{keyring_class.__name__} (priority: {keyring_class.priority:g})"

@abc.abstractmethod
def get_password(self, service: str, username: str) -> typing.Optional[str]:
def get_password(self, service: str, username: str) -> str | None:
"""Get password of the username for the service"""
return None

@@ -127,8 +126,8 @@ def delete_password(self, service: str, username: str) -> None:
def get_credential(
self,
service: str,
username: typing.Optional[str],
) -> typing.Optional[credentials.Credential]:
username: str | None,
) -> credentials.Credential | None:
"""Gets the username and password for the service.
Returns a Credential instance.
@@ -146,14 +145,12 @@ def get_credential(
def set_properties_from_env(self) -> None:
"""For all KEYRING_PROPERTY_* env var, set that property."""

def parse(item: typing.Tuple[str, str]):
def parse(item: tuple[str, str]):
key, value = item
pre, sep, name = key.partition('KEYRING_PROPERTY_')
return sep and (name.lower(), value)

props: filter[typing.Tuple[str, str]] = filter(
None, map(parse, os.environ.items())
)
props: filter[tuple[str, str]] = filter(None, map(parse, os.environ.items()))
for name, value in props:
setattr(self, name, value)

@@ -213,8 +210,8 @@ def _load_plugins() -> None:
log.exception(f"Error initializing plugin {ep}.")


@util.once
def get_all_keyring() -> typing.List[KeyringBackend]:
@once
def get_all_keyring() -> list[KeyringBackend]:
"""
Return a list of all implemented keyrings that can be constructed without
parameters.
@@ -249,8 +246,8 @@ class SchemeSelectable:
)

def _query(
self, service: str, username: typing.Optional[str] = None, **base: typing.Any
) -> typing.Dict[str, str]:
self, service: str, username: str | None = None, **base: typing.Any
) -> dict[str, str]:
scheme = self.schemes[self.scheme]
return dict(
{
16 changes: 8 additions & 8 deletions keyring/backends/SecretService.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from contextlib import closing
import logging
from contextlib import closing

from .. import backend
from .._compat import properties
from ..backend import KeyringBackend
from ..compat import properties
from ..credentials import SimpleCredential
from ..errors import (
InitError,
PasswordDeleteError,
ExceptionRaisedContext,
InitError,
KeyringLocked,
PasswordDeleteError,
)

try:
@@ -32,7 +32,7 @@ class Keyring(backend.SchemeSelectable, KeyringBackend):
@properties.classproperty
def priority(cls) -> float:
with ExceptionRaisedContext() as exc:
secretstorage.__name__
secretstorage.__name__ # noqa: B018
if exc:
raise RuntimeError("SecretStorage required")
if secretstorage.__version_tuple__ < (3, 2):
@@ -45,7 +45,7 @@ def priority(cls) -> float:
"activatable through D-Bus"
)
except exceptions.SecretStorageException as e:
raise RuntimeError("Unable to initialize SecretService: %s" % e)
raise RuntimeError(f"Unable to initialize SecretService: {e}") from e
return 5

def get_preferred_collection(self):
@@ -60,7 +60,7 @@ def get_preferred_collection(self):
else:
collection = secretstorage.get_default_collection(bus)
except exceptions.SecretStorageException as e:
raise InitError("Failed to create the collection: %s." % e)
raise InitError(f"Failed to create the collection: {e}.") from e
if collection.is_locked():
collection.unlock()
if collection.is_locked(): # User dismissed the prompt
@@ -86,7 +86,7 @@ def set_password(self, service, username, password):
"""Set password for the username of the service"""
collection = self.get_preferred_collection()
attributes = self._query(service, username, application=self.appid)
label = "Password for '{}' on '{}'".format(username, service)
label = f"Password for '{username}' on '{service}'"
with closing(collection.connection):
collection.create_item(label, attributes, password, replace=True)

14 changes: 6 additions & 8 deletions keyring/backends/Windows.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import logging

from .._compat import properties
from ..backend import KeyringBackend
from ..compat import properties
from ..credentials import SimpleCredential
from ..errors import PasswordDeleteError, ExceptionRaisedContext

from ..errors import ExceptionRaisedContext, PasswordDeleteError

with ExceptionRaisedContext() as missing_deps:
try:
# prefer pywin32-ctypes
from win32ctypes.pywin32 import pywintypes
from win32ctypes.pywin32 import win32cred
from win32ctypes.pywin32 import pywintypes, win32cred

# force demand import to raise ImportError
win32cred.__name__
win32cred.__name__ # noqa: B018
except ImportError:
# fallback to pywin32
import pywintypes
import win32cred

# force demand import to raise ImportError
win32cred.__name__
win32cred.__name__ # noqa: B018

log = logging.getLogger(__name__)

@@ -39,7 +37,7 @@ def __set__(self, keyring, value):
if isinstance(value, str):
attr = 'CRED_PERSIST_' + value.replace(' ', '_').upper()
value = getattr(win32cred, attr)
setattr(keyring, '_persist', value)
keyring._persist = value


class DecodingCredential(dict):
2 changes: 1 addition & 1 deletion keyring/backends/chainer.py
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
"""

from .. import backend
from .._compat import properties
from ..compat import properties
from . import fail


2 changes: 1 addition & 1 deletion keyring/backends/fail.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from ..backend import KeyringBackend
from .._compat import properties
from ..compat import properties
from ..errors import NoKeyringError


13 changes: 6 additions & 7 deletions keyring/backends/kwallet.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import sys
import os
import contextlib
import os
import sys

from ..backend import KeyringBackend
from ..compat import properties
from ..credentials import SimpleCredential
from ..errors import PasswordDeleteError
from ..errors import PasswordSetError, InitError, KeyringLocked
from .._compat import properties
from ..errors import InitError, KeyringLocked, PasswordDeleteError, PasswordSetError

try:
import dbus
@@ -44,7 +43,7 @@ def priority(cls) -> float:
try:
bus = dbus.SessionBus(mainloop=DBusGMainLoop())
except dbus.DBusException as exc:
raise RuntimeError(exc.get_dbus_message())
raise RuntimeError(exc.get_dbus_message()) from exc
if not (
bus.name_has_owner(cls.bus_name)
or cls.bus_name in bus.list_activatable_names()
@@ -97,7 +96,7 @@ def connected(self, service):
self.iface = dbus.Interface(remote_obj, 'org.kde.KWallet')
self.handle = self.iface.open(self.iface.networkWallet(), wId, self.appid)
except dbus.DBusException as e:
raise InitError('Failed to open keyring: %s.' % e)
raise InitError(f'Failed to open keyring: {e}.') from e

if self.handle < 0:
return False
9 changes: 4 additions & 5 deletions keyring/backends/libsecret.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import logging

from .. import backend
from .._compat import properties
from ..backend import KeyringBackend
from ..compat import properties
from ..credentials import SimpleCredential
from ..errors import (
KeyringLocked,
PasswordDeleteError,
PasswordSetError,
KeyringLocked,
)

available = False
try:
import gi
from gi.repository import Gio
from gi.repository import GLib
from gi.repository import Gio, GLib

gi.require_version('Secret', '1')
from gi.repository import Secret
@@ -84,7 +83,7 @@ def get_password(self, service, username):
def set_password(self, service, username, password):
"""Set password for the username of the service"""
attributes = self._query(service, username, application=self.appid)
label = "Password for '{}' on '{}'".format(username, service)
label = f"Password for '{username}' on '{service}'"
try:
stored = Secret.password_store_sync(
self.schema, attributes, self.collection, label, password, None
Loading