summaryrefslogtreecommitdiff
path: root/README.rst
blob: 35845d61f438f69039a36179d8535b922718ef1e (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
immutables
==========

.. image:: https://travis-ci.org/MagicStack/immutables.svg?branch=master
    :target: https://travis-ci.org/MagicStack/immutables

.. image:: https://ci.appveyor.com/api/projects/status/tgbc6tq56u63qqhf?svg=true
    :target: https://ci.appveyor.com/project/MagicStack/immutables

.. image:: https://img.shields.io/pypi/v/immutables.svg
    :target: https://pypi.python.org/pypi/immutables

An immutable mapping type for Python.

The underlying datastructure is a Hash Array Mapped Trie (HAMT)
used in Clojure, Scala, Haskell, and other functional languages.
This implementation is used in CPython 3.7 in the ``contextvars``
module (see PEP 550 and PEP 567 for more details).

Immutable mappings based on HAMT have O(log N) performance for both
``set()`` and ``get()`` operations, which is essentially O(1) for
relatively small mappings.

Below is a visualization of a simple get/set benchmark comparing
HAMT to an immutable mapping implemented with a Python dict
copy-on-write approach (the benchmark code is available
`here <https://gist.github.com/1st1/292e3f0bbe43bd65ff3256f80aa2637d>`_):

.. image:: bench.png


Installation
------------

``immutables`` requires Python 3.5+ and is available on PyPI::

    $ pip install immutables


API
---

``immutables.Map`` is an unordered immutable mapping.  ``Map`` objects
are hashable, comparable, and pickleable.

The ``Map`` object implements the ``collections.abc.Mapping`` ABC
so working with it is very similar to working with Python dicts:

.. code-block:: python

    import immutables

    map = immutables.Map(a=1, b=2)

    print(map['a'])
    # will print '1'

    print(map.get('z', 100))
    # will print '100'

    print('z' in map)
    # will print 'False'

Since Maps are immutable, there is a special API for mutations that
allow apply changes to the Map object and create new (derived) Maps:

.. code-block:: python

    map2 = map.set('a', 10)
    print(map, map2)
    # will print:
    #   <immutables.Map({'a': 1, 'b': 2})>
    #   <immutables.Map({'a': 10, 'b': 2})>

    map3 = map2.delete('b')
    print(map, map2, map3)
    # will print:
    #   <immutables.Map({'a': 1, 'b': 2})>
    #   <immutables.Map({'a': 10, 'b': 2})>
    #   <immutables.Map({'a': 10})>

Maps also implement APIs for bulk updates: ``MapMutation`` objects:

.. code-block:: python

    map_mutation = map.mutate()
    map_mutation['a'] = 100
    del map_mutation['b']
    map_mutation.set('y', 'y')

    map2 = map_mutation.finish()

    print(map, map2)
    # will print:
    #   <immutables.Map({'a': 1, 'b': 2})>
    #   <immutables.Map({'a': 100, 'y': 'y'})>

``MapMutation`` objects are context managers.  Here's the above example
rewritten in a more idiomatic way:

.. code-block:: python

    with map.mutate() as mm:
        mm['a'] = 100
        del mm['b']
        mm.set('y', 'y')
        map2 = mm.finish()

    print(map, map2)
    # will print:
    #   <immutables.Map({'a': 1, 'b': 2})>
    #   <immutables.Map({'a': 100, 'y': 'y'})>


Further development
-------------------

* An immutable version of Python ``set`` type with efficient
  ``add()`` and ``discard()`` operations.


License
-------

Apache 2.0
packages/chez.scm, gnu/packages/clojure.scm, gnu/packages/code.scm, gnu/packages/compression.scm, gnu/packages/compton.scm, gnu/packages/coq.scm, gnu/packages/cpp.scm, gnu/packages/cran.scm, gnu/packages/crypto.scm, gnu/packages/curl.scm, gnu/packages/databases.scm, gnu/packages/datastructures.scm, gnu/packages/debug.scm, gnu/packages/disk.scm, gnu/packages/distributed.scm, gnu/packages/django.scm, gnu/packages/dlang.scm, gnu/packages/dns.scm, gnu/packages/docker.scm, gnu/packages/education.scm, gnu/packages/efi.scm, gnu/packages/elixir.scm, gnu/packages/emacs-xyz.scm, gnu/packages/embedded.scm, gnu/packages/emulators.scm, gnu/packages/engineering.scm, gnu/packages/erlang.scm, gnu/packages/fabric-management.scm, gnu/packages/file-systems.scm, gnu/packages/finance.scm, gnu/packages/firmware.scm, gnu/packages/flashing-tools.scm, gnu/packages/fonts.scm, gnu/packages/fontutils.scm, gnu/packages/fpga.scm, gnu/packages/game-development.scm, gnu/packages/games.scm, gnu/packages/genealogy.scm, gnu/packages/genimage.scm, gnu/packages/geo.scm, gnu/packages/gimp.scm, gnu/packages/gl.scm, gnu/packages/gnome-xyz.scm, gnu/packages/gnome.scm, gnu/packages/gnuzilla.scm, gnu/packages/golang.scm, gnu/packages/gpodder.scm, gnu/packages/graph.scm, gnu/packages/graphics.scm, gnu/packages/graphviz.scm, gnu/packages/groff.scm, gnu/packages/groovy.scm, gnu/packages/gtk.scm, gnu/packages/guile-xyz.scm, gnu/packages/guile.scm, gnu/packages/hardware.scm, gnu/packages/haskell-apps.scm, gnu/packages/haskell-xyz.scm, gnu/packages/hexedit.scm, gnu/packages/i2p.scm, gnu/packages/ibus.scm, gnu/packages/image-processing.scm, gnu/packages/image-viewers.scm, gnu/packages/image.scm, gnu/packages/ipfs.scm, gnu/packages/java-graphics.scm, gnu/packages/java-maths.scm, gnu/packages/java.scm, gnu/packages/javascript.scm, gnu/packages/jrnl.scm, gnu/packages/julia.scm, gnu/packages/jupyter.scm, gnu/packages/kodi.scm, gnu/packages/language.scm, gnu/packages/lego.scm, gnu/packages/less.scm, gnu/packages/libusb.scm, gnu/packages/linux.scm, gnu/packages/lirc.scm, gnu/packages/lisp-xyz.scm, gnu/packages/llvm.scm, gnu/packages/logging.scm, gnu/packages/lolcode.scm, gnu/packages/lua.scm, gnu/packages/lxde.scm, gnu/packages/lxqt.scm, gnu/packages/machine-learning.scm, gnu/packages/mail.scm, gnu/packages/markup.scm, gnu/packages/maths.scm, gnu/packages/maven.scm, gnu/packages/mes.scm, gnu/packages/messaging.scm, gnu/packages/monitoring.scm, gnu/packages/mpd.scm, gnu/packages/music.scm, gnu/packages/networking.scm, gnu/packages/node-xyz.scm, gnu/packages/ocaml.scm, gnu/packages/ocr.scm, gnu/packages/onc-rpc.scm, gnu/packages/opencl.scm, gnu/packages/opencog.scm, gnu/packages/pantheon.scm, gnu/packages/password-utils.scm, gnu/packages/patchutils.scm, gnu/packages/pdf.scm, gnu/packages/perl6.scm, gnu/packages/phabricator.scm, gnu/packages/popt.scm, gnu/packages/printers.scm, gnu/packages/prolog.scm, gnu/packages/protobuf.scm, gnu/packages/pulseaudio.scm, gnu/packages/python-crypto.scm, gnu/packages/python-web.scm, gnu/packages/python-xyz.scm, gnu/packages/qt.scm, gnu/packages/radio.scm, gnu/packages/rails.scm, gnu/packages/rdf.scm, gnu/packages/rednotebook.scm, gnu/packages/rpc.scm, gnu/packages/rsync.scm, gnu/packages/ruby.scm, gnu/packages/rust.scm, gnu/packages/scheme.scm, gnu/packages/screen.scm, gnu/packages/security-token.scm, gnu/packages/selinux.scm, gnu/packages/serialization.scm, gnu/packages/shells.scm, gnu/packages/shellutils.scm, gnu/packages/simh.scm, gnu/packages/sml.scm, gnu/packages/ssh.scm, gnu/packages/statistics.scm, gnu/packages/stenography.scm, gnu/packages/sync.scm, gnu/packages/syncthing.scm, gnu/packages/synergy.scm, gnu/packages/telephony.scm, gnu/packages/terminals.scm, gnu/packages/tex.scm, gnu/packages/texinfo.scm, gnu/packages/text-editors.scm, gnu/packages/textutils.scm, gnu/packages/time.scm, gnu/packages/tmux.scm, gnu/packages/tor.scm, gnu/packages/toys.scm, gnu/packages/version-control.scm, gnu/packages/video.scm, gnu/packages/vim.scm, gnu/packages/virtualization.scm, gnu/packages/vlang.scm, gnu/packages/vnc.scm, gnu/packages/vpn.scm, gnu/packages/web-browsers.scm, gnu/packages/web.scm, gnu/packages/wireservice.scm, gnu/packages/wm.scm, gnu/packages/wxwidgets.scm, gnu/packages/xdisorg.scm, gnu/packages/xml.scm, gnu/packages/xorg.scm, tests/lint.scm: Remove trailing ".git" from 'git-reference' URL. 2020-07-12lint: source: Validate URLs of Git references.Ludovic Courtès Until now the 'source' checker would look at URL for 'url-fetch' origins but not for 'git-fetch' origins. * guix/lint.scm (check-source): Add case for 'git-reference?'. * tests/lint.scm ("source, git-reference: 301 -> 200"): New test. 2020-06-26tests: Skip lint tests when HTTP server cannot listen.Ludovic Courtès This could happen when running tests in parallel. * tests/lint.scm ("github-url") ("github-url: one suggestion") ("github-url: already the correct github url") ("archival: missing content") ("archival: content available") ("archival: missing revision") ("archival: revision available") ("archival: rate limit reached"): Add 'test-skip' statement above. 2020-06-14lint: Add 'check-for-collisions' checker.Ludovic Courtès Suggested by Edouard Klein <edk@beaver-labs.com>. * guix/profiles.scm (check-for-collisions): Export. * guix/lint.scm (check-profile-collisions): New procedure. (%local-checkers): Add 'profile-collisions' checker. * tests/lint.scm ("profile-collisions: no warnings") ("profile-collisions: propagated inputs collide") ("profile-collisions: propagated inputs collide, store items"): New tests. * doc/guix.texi (Invoking guix lint): Document it. 2020-01-17lint: vulnerabilities: Avoid 'mock' in test.Ludovic Courtès * guix/lint.scm (check-vulnerabilities): Add 'package-vulnerabilities' optional parameter. * tests/lint.scm ("cve: one vulnerability"): Use it instead of 'mock'. 2019-10-20tests: Avoid now-deprecated 'make-struct'.Ludovic Courtès * tests/cve.scm (vulnerability): Use 'make-struct/no-tail' instead of 'make-struct', which is deprecated. * tests/lint.scm ("cve: one vulnerability") ("cve: one patched vulnerability") ("cve: known safe from vulnerability") ("cve: vulnerability fixed in replacement version") ("cve: patched vulnerability in replacement"): Likewise. 2019-09-02lint: Add 'archival' checker.Ludovic Courtès * guix/lint.scm (check-archival): New procedure. (%network-dependent-checkers): Add 'archival' checker. * tests/lint.scm ("archival: missing content") ("archival: content available") ("archival: missing revision") ("archival: revision available") ("archival: rate limit reached"): New tests. * doc/guix.texi (Invoking guix lint): Document it. 2019-09-02tests: 'with-http-server' accepts multiple responses.Ludovic Courtès * guix/tests/http.scm (call-with-http-server): Replace 'code' and 'data' parameters with 'responses+data'. Compute RESPONSES as a function of that. Remove #:headers parameter. [http-write]: Quit only when RESPONSES is empty. [server-body]: Get the response and data from RESPONSES, and set it to point to the rest. (with-http-server): Adjust accordingly. * tests/derivations.scm ("'download' built-in builder") ("'download' built-in builder, invalid hash") ("'download' built-in builder, not found") ("'download' built-in builder, check mode"): Adjust to new 'with-http-server' interface. * tests/lint.scm ("home-page: 200") ("home-page: 200 but short length") ("home-page: 404", "home-page: 301, invalid"): ("home-page: 301 -> 200", "home-page: 301 -> 404") ("source: 200", "source: 200 but short length") ("source: 404", "source: 404 and 200") ("source: 301 -> 200", "source: 301 -> 404"): ("github-url", github-url): Likewise. * tests/swh.scm (with-json-result) ("lookup-origin, not found"): Likewise. 2019-08-17tests: Relax expectations for the 'home-page' checker.Ludovic Courtès Fixes a regression introduced in 50fc2384feb3bb2677d074f8f0deb5ae3c56b4d8. * tests/lint.scm (warning-contains?): New procedure. ("home-page: host not found"): Use 'warning-contains?' instead of testing for equality, as was the case before commit 50fc2384feb. This handles the case where the 'getaddrinfo' error is not "Name or service not known" but instead something like "System error" or "Servname not supported for ai_socktype", as is the case in the build environment. 2019-07-20lint: Add test for 'source'.Ludovic Courtès * tests/lint.scm ("source: 404 and 200"): New test. 2019-07-20lint: Update tests to (guix lint) migration.Ludovic Courtès This is a followup to f363c836e0b4c416dae594af4257459da592b35c. * tests/lint.scm ("cve") ("cve: one vulnerability") ("cve: one patched vulnerability") ("cve: known safe from vulnerability") ("cve: vulnerability fixed in replacement version") ("cve: patched vulnerability in replacement"): Refer to 'package-vulnerabilities' from (guix lint), not (guix scripts lint). 2019-07-15lint: Move the linting code to a different module.Christopher Baines To try and move towards making programatic access to the linting code easier, this commit separates out the linting script, from the linting functionality that it uses. * guix/scripts/lint.scm (emit-warnings): Alter to to not use match-lambda, as <lint-warning> isn't accessible. (<lint-warning>, lint-warning, make-lint-warning, lint-warning?, lint-warning-message, lint-warning-message-text, lint-warning-message-data, lint-warning-location, package-file, %make-warning make-warning, <lint-checker>, lint-checker, make-lint-checker, lint-checker?, lint-checker-name, lint-checker-description, lint-checker-check, properly-starts-sentance?, starts-with-abbreviation?, %quoted-identifier-rx, check-description-style, package-input-intersection, check-inputs-should-be-native, check-inputs-should-not-be-an-input-at-all, package-name-regexp, check-synopsis-style, probe-uri, tls-certificate-error-string, validate-uri, check-home-page, %distro-directory, check-patch-file-names, escape-quotes, official-gnu-packages*, check-gnu-synopsis+description, origin-uris, check-source, check-source-file-name, check-source-unstable-tarball, check-mirror-url, check-github-url, check-derivation, check-license, call-with-networking-fail-safe, with-networking-fail-safe, current-vulnerabilities*, package-vulnerabilities, check-vulnerabilities, check-for-updates, report-tabulations, report-trailing-white-space, report-long-line, %hanging-paren-rx, report-lone-parantheses, %formatting-reporters, report-formatting-issues, check-formatting, %checkers): Move to… * guix/lint.scm: … here * po/guix/POTFILES.in: Add guix/lint.scm. * Makefile.am: Add guix/lint.scm. * tests/lint.scm: Change to import (guix lint), rather than (guix scripts lint). 2019-07-15scripts: lint: Handle warnings with a record type.Christopher Baines Rather than emiting warnings directly to a port, have the checkers return the warning or warnings. This makes it easier to use the warnings in different ways, for example, loading the data in to a database, as you can work with the <lint-warning> records directly, rather than having to parse the output to determine the package and location. * guix/scripts/lint.scm (<lint-warning>): New record type. (lint-warning): New macro. (lint-warning?, lint-warning-package, lint-warning-message, lint-warning-location, package-file, make-warning): New procedures. (call-with-accumulated-warnings, with-accumulated-warnings): Remove. (emit-warning): Rename to emit-warnings, and switch to displaying multiple warnings. (check-description-style)[check-not-empty-description, check-texinfo-markup, check-trademarks, check-quotes, check-proper-start, check-end-of-sentence-space]: Switch to generating a list of warnings, and using make-warning, rather than emit-warning. (check-inputs-should-be-native, check-inputs-should-not-be-an-input-at-all): Switch to generating a list of warnings, and using make-warning, rather than emit-warning. (check-synopsis): Switch to generating a list of warnings, and using make-warning, rather than emit-warning. [check-not-empty]: Remove, this is handled in the match clause to avoid other warnings being emitted. [check-final-period, check-start-article, check-synopsis-length, check-proper-start, check-start-with-package-name, check-texinfo-markup]: Switch to generating a list of warnings, and using make-warning, rather than emit-warning. [checks]: Remove check-not-empty. (validate-uri, check-home-page, check-patch-file-names, check-gnu-synopsis+description): Switch to generating a list of warnings, and using make-warning, rather than emit-warning. (check-source): Switch to generating a list of warnings, and using make-warning, rather than emit-warning. [try-uris]: Remove. [warnings-for-uris]: New procedure, replacing try-uris. (check-source-file-name, check-source-unstable-tarball, check-mirror-url, check-github-url, check-derivation, check-vulnerabilities, check-for-updates, report-tabulations, report-trailing-white-space, report-long-line, report-lone-parentheses, report-formatting-issues, check-formatting): Switch to generating a list of warnings, and using make-warning, rather than emit-warning. (run-checkers): Call emit-warnings on the warnings returned from the checker. * tests/lint.scm (string-match-or-error, single-lint-warning-message): New procedures. (call-with-warnings, with-warnings): Remove. ("description: not a string", "description: not empty", "description: invalid Texinfo markup", "description: does not start with an upper-case letter", "description: may start with a digit", "description: may start with lower-case package name", "description: two spaces after end of sentence", "description: end-of-sentence detection with abbreviations", "description: may not contain trademark signs: ™", "description: may not contain trademark signs: ®", "description: suggest ornament instead of quotes", "synopsis: not a string", "synopsis: not empty", "synopsis: valid Texinfo markup", "synopsis: does not start with an upper-case letter", "synopsis: may start with a digit", "synopsis: ends with a period", "synopsis: ends with 'etc.'", "synopsis: starts with 'A'", "synopsis: starts with 'a'", "synopsis: starts with 'an'", "synopsis: too long", "synopsis: start with package name", "synopsis: start with package name prefix", "synopsis: start with abbreviation", "inputs: pkg-config is probably a native input", "inputs: glib:bin is probably a native input", "inputs: python-setuptools should not be an input at all (input)", "inputs: python-setuptools should not be an input at all (native-input)", "inputs: python-setuptools should not be an input at all (propagated-input)", "patches: file names", "patches: file name too long", "patches: not found", "derivation: invalid arguments", "license: invalid license", "home-page: wrong home-page", "home-page: invalid URI", "home-page: host not found", "home-page: Connection refused", "home-page: 200", "home-page: 200 but short length", "home-page: 404", "home-page: 301, invalid", "home-page: 301 -> 200", "home-page: 301 -> 404", "source-file-name", "source-file-name: v prefix", "source-file-name: bad checkout", "source-file-name: good checkout", "source-file-name: valid", "source-unstable-tarball", "source-unstable-tarball: source #f", "source-unstable-tarball: valid", "source-unstable-tarball: package named archive", "source-unstable-tarball: not-github", "source-unstable-tarball: git-fetch", "source: 200", "source: 200 but short length", "source: 404", "source: 301 -> 200", "source: 301 -> 404", "mirror-url", "mirror-url: one suggestion", "github-url", "github-url: one suggestion", "github-url: already the correct github url", "cve", "cve: one vulnerability", "cve: one patched vulnerability", "cve: known safe from vulnerability", "cve: vulnerability fixed in replacement version", "cve: patched vulnerability in replacement", "formatting: lonely parentheses", "formatting: alright"): Change test-assert to test-equal, and adjust to work with the changes above. ("formatting: tabulation", "formatting: trailing white space", "formatting: long line"): Use string-match-or-error rather than string-contains.