Skip to content

Commit

Permalink
Merge pull request #275 from corenting/feat/prepare-next-release
Browse files Browse the repository at this point in the history
feat: prepare next release
  • Loading branch information
corenting committed Oct 18, 2023
2 parents ba31ea3 + d53c3a1 commit 39605db
Show file tree
Hide file tree
Showing 13 changed files with 732 additions and 154 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ jobs:
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
if: ${{ matrix.python-version != '3.12' }} # remove when codeql is fixed on 3.12
with:
languages: python
- name: Install Poetry
Expand All @@ -45,7 +44,6 @@ jobs:
run: make test
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
if: ${{ matrix.python-version != '3.12' }} # remove when codeql is fixed on 3.12
- name: Codecov
uses: codecov/codecov-action@v3
with:
Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/doc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: "Documentation"

on:
push:
branches:
- "master"
tags:
- "v*"
pull_request:
branches:
- "master"

jobs:
build:
name: Build sphinx documentation
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Poetry
run: pipx install poetry
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.12
cache: "poetry"
- name: Setup environment
run: poetry install
- name: Build HTML
run: poetry run sphinx-build -M html docs docs/build
- name: Upload artifacts
uses: actions/upload-pages-artifact@v2
with:
path: docs/build/html/
deploy:
name: Deploy documentation
runs-on: ubuntu-latest
needs: build
if: startsWith(github.ref, 'refs/tags/v')
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2 # or the latest "vX.X.X" version tag for this action


3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Version 3.1.0
# Version 3.1.0 (unreleased)

- Replace `__init__` by `__new__`. Thanks to [@spacether](https://github.com/spacether) for the [PR #263](https://github.com/corenting/immutabledict/pull/263)
- Add explicit items()/keys()/values() methods to speedup these methods. Thanks to [@matthiasdiener](https://github.com/matthiasdiener) for the [PR #265](https://github.com/corenting/immutabledict/pull/265)
- Add set/delete/update functions. Thanks to [@matthiasdiener](https://github.com/matthiasdiener) for the [PR #271](https://github.com/corenting/immutabledict/pull/271)

# Version 3.0.0

Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

![License](https://img.shields.io/pypi/l/immutabledict) ![Build](https://img.shields.io/github/actions/workflow/status/corenting/immutabledict/ci.yml?branch=master) ![Codecov](https://img.shields.io/codecov/c/github/corenting/immutabledict) ![PyPI - Downloads](https://img.shields.io/pypi/dm/immutabledict)

A fork of the original [frozendict](https://github.com/slezica/python-frozendict), an immutable wrapper around dictionaries.
This library is a pure Python, MIT-licensed alternative to the new LGPL-3.0 licensed [frozendict](https://github.com/Marco-Sulla/python-frozendict).
An immutable wrapper around dictionaries. immutabledict implements the complete mapping interface and can be used as a drop-in replacement for dictionaries where immutability is desired.

It implements the complete mapping interface and can be used as a drop-in replacement for dictionaries where immutability is desired.
The immutabledict constructor mimics dict, and all of the expected interfaces (iter, len, repr, hash, getitem) are provided. Note that an immutabledict does not guarantee the immutability of its values, so the utility of hash method is restricted by usage.
It's a fork of slezica's [frozendict](https://github.com/slezica/python-frozendict). This library is a pure Python, MIT-licensed alternative to the new LGPL-3.0 licensed [frozendict](https://github.com/Marco-Sulla/python-frozendict).

## Installation

Expand Down
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
7 changes: 7 additions & 0 deletions docs/api/immutable_ordered_dict.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ImmutableOrderedDict
======================

.. autoclass:: immutabledict.ImmutableOrderedDict
:exclude-members: dict_cls
:show-inheritance:
:member-order: bysource
6 changes: 6 additions & 0 deletions docs/api/immutabledict.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
immutabledict
======================

.. autoclass:: immutabledict.immutabledict
:exclude-members: items,keys,values
:member-order: bysource
52 changes: 52 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""sphinx configuration."""
from immutabledict import __version__

# Project info
project = "immutabledict"
copyright = "2023, corenting"
author = "corenting"
version = __version__
release = __version__

# General configuration
extensions = [
"alabaster",
"sphinx.ext.intersphinx",
"sphinx.ext.autodoc",
]

templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

# Autodoc settings
autodoc_default_options = {
"members": True,
}

# intersphinx to Python
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}

# HTML output
html_theme = "alabaster"
html_sidebars = {
"**": [
"about.html",
"navigation.html",
"relations.html",
"searchbox.html",
"donate.html",
]
}
html_theme_options = {
"description": "An immutable wrapper around dictionaries",
"github_user": "corenting",
"github_repo": "immutabledict",
"codecov_button": True,
"badge_branch": "master",
"sidebar_width": "300px",
"donate_url": "https://corenting.fr/donate",
"extra_nav_links": {
"Github repository": "https://github.com/corenting/immutabledict",
"PyPI page": "https://pypi.org/project/immutabledict/",
},
}
31 changes: 31 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Welcome to immutabledict’s documentation!
=========================================

This site covers immutabledict’s API documentation. For more information about immutabledict, see `the Github repository <https://github.com/corenting/immutabledict>`_.

Usage
-----

The :class:`.immutabledict` class can be used as a drop-in replacement for :class:`dict`.

For replacing an :class:`collections.OrderedDict`, you can use an :class:`.ImmutableOrderedDict`. The API is the same as :class:`.immutabledict`, but it will use an :class:`collections.OrderedDict` under the hood.

.. code-block:: python
from immutabledict import immutabledict
my_item = immutabledict({"a": "value", "b": "other_value"})
print(my_item["a"]) # Print "value"
Some additional methods are provided, see the API reference.


API reference
-------------

.. toctree::
:maxdepth: 1

/api/immutabledict
/api/immutable_ordered_dict

56 changes: 40 additions & 16 deletions immutabledict/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Implementation of the :class:`immutabledict` and :class:`ImmutableOrderedDict` classes."""
from __future__ import annotations

from collections import OrderedDict
Expand All @@ -7,12 +8,12 @@
ItemsView,
Iterable,
Iterator,
KeysView,
Mapping,
Optional,
Type,
TypeVar,
ValuesView,
KeysView,
)

__version__ = "3.0.0"
Expand All @@ -21,27 +22,26 @@
_V = TypeVar("_V", covariant=True)


class immutabledict(Mapping[_K, _V]):
class immutabledict(Mapping[_K, _V]): # noqa: N801
"""
An immutable wrapper around dictionaries that implements
the complete :py:class:`collections.Mapping` interface.
It can be used as a drop-in replacement for dictionaries
where immutability is desired.
An immutable wrapper around dictionaries that implements the complete :py:class:`collections.Mapping` interface.
It can be used as a drop-in replacement for dictionaries where immutability is desired.
"""

dict_cls: Type[Dict[Any, Any]] = dict
_dict_cls: Type[Dict[Any, Any]] = dict
_dict: Dict[_K, _V]
_hash: Optional[int]

@classmethod
def fromkeys(
def fromkeys( # noqa: D102
cls, seq: Iterable[_K], value: Optional[_V] = None
) -> immutabledict[_K, _V]:
return cls(cls.dict_cls.fromkeys(seq, value))
return cls(cls._dict_cls.fromkeys(seq, value))

def __new__(cls, *args: Any, **kwargs: Any) -> immutabledict[_K, _V]:
def __new__(cls, *args: Any, **kwargs: Any) -> immutabledict[_K, _V]: # noqa: D102
inst = super().__new__(cls)
setattr(inst, "_dict", cls.dict_cls(*args, **kwargs))
setattr(inst, "_dict", cls._dict_cls(*args, **kwargs))
setattr(inst, "_hash", None)
return inst

Expand All @@ -51,7 +51,7 @@ def __getitem__(self, key: _K) -> _V:
def __contains__(self, key: object) -> bool:
return key in self._dict

def copy(self) -> immutabledict[_K, _V]:
def copy(self) -> immutabledict[_K, _V]: # noqa: D102
return self.__class__(self)

def __iter__(self) -> Iterator[_K]:
Expand All @@ -61,7 +61,7 @@ def __len__(self) -> int:
return len(self._dict)

def __repr__(self) -> str:
return "{}({!r})".format(self.__class__.__name__, self._dict)
return f"{self.__class__.__name__}({self._dict!r})"

def __hash__(self) -> int:
if self._hash is None:
Expand Down Expand Up @@ -89,26 +89,48 @@ def __ror__(self, other: Any) -> Dict[Any, Any]:
def __ior__(self, other: Any) -> immutabledict[_K, _V]:
raise TypeError(f"'{self.__class__.__name__}' object is not mutable")

def items(self) -> ItemsView[_K, _V]:
def items(self) -> ItemsView[_K, _V]: # noqa: D102
return self._dict.items()

def keys(self) -> KeysView[_K]:
def keys(self) -> KeysView[_K]: # noqa: D102
return self._dict.keys()

def values(self) -> ValuesView[_V]:
def values(self) -> ValuesView[_V]: # noqa: D102
return self._dict.values()

def set(self, key: _K, value: Any) -> immutabledict[_K, _V]:
"""
Return a new :class:`immutabledict` where the item at the given key is set to to the given value. If there is already an item at the given key it will be replaced.
:param key: the key for which we want to set a value
:param value: the value we want to use
:return: the new :class:`immutabledict` with the key set to the given value
"""
new = dict(self._dict)
new[key] = value
return self.__class__(new)

def delete(self, key: _K) -> immutabledict[_K, _V]:
"""
Return a new :class:`immutabledict` without the item at the given key.
:param key: the key of the item you want to remove in the returned :class:`immutabledict`
:raises [KeyError]: a KeyError is raised if there is no item at the given key
:return: the new :class:`immutabledict` without the item at the given key
"""
new = dict(self._dict)
del new[key]
return self.__class__(new)

def update(self, _dict: Dict[_K, _V]) -> immutabledict[_K, _V]:
"""
Similar to :meth:`dict.update` but returning an immutabledict.
:return: the updated :class:`immutabledict`
"""
new = dict(self._dict)
new.update(_dict)
return self.__class__(new)
Expand All @@ -117,6 +139,8 @@ def update(self, _dict: Dict[_K, _V]) -> immutabledict[_K, _V]:
class ImmutableOrderedDict(immutabledict[_K, _V]):
"""
An immutabledict subclass that maintains key order.
Same as :class:`immutabledict` but based on :class:`collections.OrderedDict`.
"""

dict_cls = OrderedDict

0 comments on commit 39605db

Please sign in to comment.