{"id":26134075,"url":"https://github.com/benhowell/pgnotifier","last_synced_at":"2026-04-12T16:03:03.069Z","repository":{"id":252863782,"uuid":"841721675","full_name":"benhowell/pgnotifier","owner":"benhowell","description":"A simple little module to capture, process, and dispatch Postgresql NOTIFY streams","archived":false,"fork":false,"pushed_at":"2024-08-23T06:03:33.000Z","size":72,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-14T16:06:39.201Z","etag":null,"topics":["notify","postgresql","python"],"latest_commit_sha":null,"homepage":"https://github.com/benhowell/pgnotifier","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/benhowell.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-08-12T23:25:44.000Z","updated_at":"2024-08-23T09:17:08.000Z","dependencies_parsed_at":"2025-10-14T16:06:39.951Z","dependency_job_id":null,"html_url":"https://github.com/benhowell/pgnotifier","commit_stats":null,"previous_names":["benhowell/pgnotifier"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/benhowell/pgnotifier","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benhowell%2Fpgnotifier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benhowell%2Fpgnotifier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benhowell%2Fpgnotifier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benhowell%2Fpgnotifier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/benhowell","download_url":"https://codeload.github.com/benhowell/pgnotifier/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benhowell%2Fpgnotifier/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279019558,"owners_count":26086750,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["notify","postgresql","python"],"created_at":"2025-03-10T23:04:00.339Z","updated_at":"2025-10-14T16:06:40.786Z","avatar_url":"https://github.com/benhowell.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pgnotifier\nA simple little module to capture, process, and dispatch Postgresql NOTIFY streams\n\u003cbr\u003e\n### Features\n* Monitor multiple channels\n* Register one or more callbacks with multiple channels\n* Register one or more channels with a callback\n* Control callbacks on a per channel basis\n* Add and remove channels at any time\n* Mute and un-mute channels\n* Add and remove subscribers at any time\n* Mute and un-mute subscribers\n* Abstract away asynchronous context for synchronous use\n* Automatic str -\u003e type conversion of all valid python types via `ast.literal_eval`\n* Persistent, immutable internal data structures\n* Minimalist API\n* Tight footprint\n\n\u003cbr\u003e\n\n## Install\n``` python\npip install pgnotifier\n```\n\n## Usage\n\n``` python\nimport sys\nfrom pgnotifier import Notifier\n\nprint(\"Ctrl-C to exit\", file=sys.stderr)\n\nconf = {\n    'dbname': \"my_db_name\",\n    'user': \"my_db_user\",\n    'password': \"my_password\",\n    'host': \"my_host\",\n    'port': \"my_port\",\n}\nn = Notifier(conf)\nn.add_channels(['ch1', 'ch3'])\n\nn.subscribe(42, 'ch1',\n    lambda id, channel, payload, pid: print(\n        \"callback id: \", id, \", channel: \", channel,\n        \", payload: \", payload, \", pid: \", pid))\n\nn.subscribe('an_id', 'ch2',\n            lambda *_: print(\"I'm just going to ignore that.\"))\n\ndef do_complex_thing(id, channel, payload, pid):\n    if isinstance(payload, dict) or type(payload) == dict:\n        for k,v in payload.items():\n            print(\"doing something with key:\",k, \"-\u003e val\",v)\n            # do something else\n            # I think you get the idea...\n    else:\n        print(\"payload of type: \",\n              type(payload), \"is not what I was expecting!\")\n\n# subscriber with tuple id\nn.subscribe((2, 'another_id'), 'ch2', do_complex_thing)\n\n```\n\n\n## Test\nFrom the Postrgesql end, send TEXT or JSON string notifications like so:\n\n``` sql\nselect pg_notify('ch1', '\"WARNING: Something really bad happened\"');\nselect pg_notify('ch1', '{\"topic\": \"abc\", \"data\": \"some data\", \"something\": \"else\"}');\nselect pg_notify('ch2', '{\"topic\": \"xyz\", \"notice\": \"update\", \"data\": [2, \"stuff\"]}');\nselect pg_notify('ch2', '[1,2,3,4,5]');\nselect pg_notify('ch3', '[1,2,3,4,5]');\n```\nBack in python, the payload is passed to callbacks subscribed to channels `ch1`, `ch2`, etc. The payload is cast to it's native python type via `ast.literal_eval`. See https://docs.python.org/3/library/ast.html and https://docs.python.org/3/library/ast.html#ast.literal_eval\n\n\u003cbr\u003e\n\n\u003e [!IMPORTANT]\n\u003e Postgresql notifications must be text and must be shorter than 8000 bytes. It is recommended to only send the key of a record, or a view or table name, a function reference, etc.\n\n\u003cbr\u003e\n\n## API\nThe methods below provide everything needed to work with pgnotifier.\n\n**[Notifier](#notifier-dbconf-)**\n- [add_channels](#notifieradd_channels-channels-)\n- [remove_channels](#notifierremove_channels-channels-autoruntrue-)\n- [channels](#notifierchannels-)\n- [subscribe](#notifiersubscribe-id-channel-fn-autoruntrue-)\n- [unsubscribe](#notifierunsubscribe-id-channel-autoruntrue-)\n- [subscribers](#notifiersubscribers-)\n- [mute_channels](#notifiermute_channels-channelspyrsistentpvector-)\n- [unmute_channels](#notifierunmute_channels-channelspyrsistentpvector-)\n- [mute_subscriber](#notifiermute_subscriber-id-channelspyrsistentpvector-)\n- [unmute_subscriber](#notifierunmute_subscriber-id-channelspyrsistentpvector-)\n- [start](#notifierstart-)\n- [stop](#notifierstop-)\n- [restart](#notifierrestart-)\n- [is_running](#notifieris_running-)\n\n\u003cbr\u003e\n\n## Internal helper functions\nThe functions below are not required outside the internals of pgnotifier. They\nare publicly exposed and included here as a matter of interest.\n\n**[Internal helper functions](#Internal-helper-functions)**\n- [assoc_in](#notifyassoc_in-m-pv-v-)\n- [dissoc_in](#notifydissoc_in-m-pv-)\n- [filterkv](#notifyfilterkv-m-f-a-)\n- [as_sync](#notifyas_async-f-a-)\n\n\u003cbr\u003e\n\n## Private methods\nDocumentation about the inner-workings of pgnotifier is kept separately from the\nREADME, and can be found over here: [Private methods](./private_methods.md). or\nvia the method links below.\n\n**[Private methods](./private_methods.md)**\n- [__maybe_stop](./private_methods.md#notifier__maybe_stop-)\n- [__maybe_restart](./private_methods.md#notifier__maybe_restart-)\n- [__notify](./private_methods.md#notifier__notify)\n- [__valid_chans](./private_methods.md#notifier__valid_chans)\n- [__mute_chans](./private_methods.md#notifier__mute_chans-channels-b-)\n- [__mute_sub](./private_methods.md#notifier__mute_sub-id-channels-b-)\n\n\u003cbr\u003e\n\n## TODO\nA list of stuff to look into at a later date can be found over here:\n[TODO](./TODO.md)\n\n\u003cbr\u003e\n\n## API\nThe methods below provide everything needed to work with pgnotifier.\n\n#### \u003cmark\u003e\u003cstrong\u003eNotifier( \u003cem style=\"font-weight:400\"\u003edbconf\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nConstructor.\n\nArgs:\n * `dbconf` database configuration, as `dict`.\n\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(dbconf)\n```\n\u003chr style=\"height:1px\"\u003e\n\n\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.add_channels( \u003cem style=\"font-weight:400\"\u003echannels\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nAdds one or more channels to the set of channels to monitor.\nIs a no-op if channel already exists.\n\nArgs:\n* `channels` list of channels to add, as `str` (single channel), `list` or `set`.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\nn.add_channels(['ch1', 'ch2', 'ch3'])\n```\n\u003chr style=\"height:1px\"\u003e\n\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.remove_channels( \u003cem style=\"font-weight:400\"\u003echannels, autorun=True\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nRemoves one or more channels from the set of channels to monitor.\nIs a no-op if channel doesn't exist. Optionally restarts listener thread (if needed).\n\nArgs:\n* `channels` list of channels to remove, as `str` (single channel), `list` or `set`.\n* `autorun` restart listener thread with channels removed, as `bool`. Defaults to `True`.\n\n\u003cbr\u003e\n\n\u003e [!IMPORTANT]\n\u003e Active channels, when removed, *will only* cease being monitored after a\nlistener thread restart. Thread restarts happen automatically when `autorun=True`.\nOtherwise, if `autorun=False`, removed channels *will* continue to be\nmonitored until a call to `stop()` and `start()`, or `restart()`, is made.\n\u003e\n\u003e Inactive channels (e.g. channel is muted and/or has no subscribers and/or\nhas all muted subscribers), when removed, *do not* require a restart as\nthey will have already been removed from the listener thread.\n\u003e\n\u003e Listener thread (re)starts are only required under certain, specific\ncircumstances. It's advisable to allow pgnotifier take care of listener\nthread management via the default `autorun=True`, *unless there is a\nvery good reason* to manage it manually.\nSee [__maybe_restart](./private_methods.md#notifier__maybe_restart-) for more detail.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added, removed, etc. ...\nn.remove_channels('ch2')\nc = n.channels()\nprint(\"channels:\", c)\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.channels( )\u003c/strong\u003e\u003c/mark\u003e\nReturns channel and subscriber data, as `dict`.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added, removed, etc. ...\nc = n.channels()\nprint(\"channels: \", c)\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.subscribe( \u003cem style=\"font-weight:400\"\u003eid, channel, fn, autorun=True\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nAdds a callback function with id for notifications on channel.\nCreates channel if channel does not exist.\nOptionally restarts listener thread (if needed).\n\nArgs:\n* `id` subscriber id, as `hashable` (i.e. any immutable type such as\nstrings, numbers, and tuples containing immutable types).\n* `channel` notification channel to subscribe to, as `str`.\n* `fn` callback function, as `callable` (i.e. function or method).\n* `autorun` restart listener thread (if needed), as `bool`. Defaults to `True`.\n\n\u003e [!IMPORTANT]\n\u003e A new channel, when added with this subscriber, or, a channel that becomes\nactive due to this subscriber *can only* be monitored after a\nlistener thread restart. Thread restarts happen automatically when `autorun=True`.\nOtherwise, if `autorun=False`, activated channels containing this subscriber\n*will not* be monitored until a call to `stop()` and `start()`, or `restart()`,\nis made.\n\u003e\n\u003e Listener thread (re)starts are only required under certain, specific\ncircumstances. It's advisable to allow pgnotifier take care of listener\nthread management via the default `autorun=True`, *unless there is a\nvery good reason* to manage it manually.\nSee [__maybe_restart](./private_methods.md#notifier__maybe_restart-) for more detail.\n\nWhen a notification is received on a channel, callbacks subscribed to that channel\nwill be executed.\n\nArgs:\n* `id` the subscriber `id` as `hashable`.\n* `channel` the notification channel, as `str`.\n* `payload` the notification received, as native type as cast by `ast.literal_eval`.\n* `pid` the notifying sessions server process PID, as `int`.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\nn.subscribe(42, 'ch4',\n    lambda id, channel, payload, pid: print(\"id: \", id, \", channel: \", channel,\n        \", payload: \", payload, \", pid: \", pid))\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.unsubscribe( \u003cem style=\"font-weight:400\"\u003eid, channel, autorun=True\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nRemoves a callback function with id from notifications on channel.\nOptionally restarts listener thread (if needed).\n\nArgs:\n* `id` the subscriber id, as `hashable`.\n* `channel` notification channel to unsubscribe from, as `str`.\n* `autorun` restart listener thread (if needed), as `bool`. Defaults to `True`.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added, removed, etc. ...\nn.unsubscribe(42, 'ch1')\n```\n\u003chr style=\"height:1px\"\u003e\n\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.subscribers( )\u003c/strong\u003e\u003c/mark\u003e\nReturns subscriber and channel data, as `dict`.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added, removed, etc. ...\ns = n.subscribers()\nprint(\"subscribers:\", s)\n\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.mute_channels( \u003cem style=\"font-weight:400\"\u003echannels=pyrsistent.PVector\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nMutes channels. Removes channels from listener thread, thereby muting all\nsubscribers associated with those channels (no matter their mute status).\n\nSubscribers will retain their mute status associated with those channels.\n\nArgs:\n* `channels` list of channels to mute, as `str` (single channel), `list` or `set`.\nIf no channels given, *ALL* channels will be muted.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added, removed, etc. ...\nn.mute_channels('ch1')\nm = n.muted_channels()\nprint(\"muted channels:\", m)\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.unmute_channels( \u003cem style=\"font-weight:400\"\u003echannels=pyrsistent.PVector\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nUn-mutes channels. Adds channels to the listener thread, thereby adding all\nun-muted subscribers associated with those channels.\n\nArgs:\n* `channels` list of channels to un-mute, as `str` (single channel), `list` or `set`.\nIf no channels given, *ALL* channels will be un-muted.\n\n\u003e [!NOTE]\n\u003e Channel will remain inactive (i.e. excluded from the listener thread) if it\n*does not* contain any non-muted subscribers.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added, removed, etc. ...\nn.unmute_channels()\nm = n.non_muted_channels()\nprint(\"non muted channels:\", m)\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.mute_subscriber( \u003cem style=\"font-weight:400\"\u003eid, channels=pyrsistent.PVector\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nMutes subscriber on channels. If a channel no longer contains any non-muted\nsubscribers, it is said to be *inactive* and is removed from the listener thread.\n\nArgs:\n* `id` subscriber id, as `hashable` (i.e. any immutable type such as\nstrings, numbers, and tuples containing immutable types).\n* `channels` list of channels to mute the subscriber on, as `str`\n(single channel), `list` or `set`.\nIf no channels given, the subscriber will be muted on *ALL* channels it is\nsubscribed to.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added, removed, etc. ...\nn.mute_subscriber('an_id', 'ch2')\nm = n.muted_subscribers()\nprint(\"muted subscribers:\", m)\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.unmute_subscriber( \u003cem style=\"font-weight:400\"\u003eid, channels=pyrsistent.PVector\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nUn-mutes subscriber on channels. If subscriber is on a non-muted, *inactive*\nchannel, the channel becomes *active* and is added to the listener thread.\n\nArgs:\n* `id` subscriber id, as `hashable` (i.e. any immutable type such as\nstrings, numbers, and tuples containing immutable types).\n* `channels` list of channels to un-mute the subscriber on, as `str`\n(single channel), `list` or `set`.\nIf no channels given, the subscriber will be unmuted on *ALL* channels it is\nsubscribed to.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added, removed, etc. ...\nn.unmute_subscriber('an_id')\nm = n.muted_subscribers()\nprint(\"muted subscribers:\", m)\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.start( )\u003c/strong\u003e\u003c/mark\u003e\nStarts the listener thread (if not already running).\nIs a no-op if thread already running.\n*This function is generally not needed in userland.*\n\n\u003e [!NOTE]\n\u003e Listener thread (re)starts are only required under certain, specific circumstances.\nSee [__maybe_restart](./private_methods.md#notifier__maybe_restart-) for more detail.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added removed, etc. ...\nn.start()\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.stop( )\u003c/strong\u003e\u003c/mark\u003e\nStops the listener thread (if running). Is a no-op if thread is not running.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been added removed, etc. ...\nn.stop()\n```\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.restart( )\u003c/strong\u003e\u003c/mark\u003e\n(Re)starts listener thread.\n*This function is generally not needed in userland.*\n\n\u003e [!NOTE]\n\u003e Listener thread (re)starts are only required under certain, specific circumstances.\nSee [__maybe_restart](./private_methods.md#notifier__maybe_restart-) for more detail.\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been changed with arg autorun=False ...\nn.restart()\n```\n\u003chr style=\"height:1px\"\u003e\n\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003eNotifier\u003c/a\u003e.is_running( )\u003c/strong\u003e\u003c/mark\u003e\nReturns True if listener thread currently running, else False, as `bool`\n\n``` python\nfrom pgnotifier import Notifier\n\nn = Notifier(conf)\n# channels and/or subscribers, have been changed with arg autorun=False ...\nb = n.is_running()\nprint(\"listener running?\",b)\n```\n\n\u003cbr\u003e\n\n## Internal helper functions\nThe functions below are not required outside the internals of pgnotifier. They\nare publicly exposed and included here as a matter of interest.\n\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003enotify\u003c/a\u003e.assoc_in( \u003cem style=\"font-weight:400\"\u003em, pv, v\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nA clojure-esque nested associative map transformer for [Pyrsistent](https://github.com/tobgu/pyrsistent). Associates a new value `v` at key path `pv` in map `m`. Returns a new map with associated changes, as `pyrsistent.PMap`.\n\nArgs:\n* `m` map to transform, as `pyrsistent.PMap`.\n* `pv` a path vector of keys indicating location of desired assoc, as `pyrsistent.PVector` or `list`\n* `v` new value to assoc into path given by `pv`, as `whatever!`\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003enotify\u003c/a\u003e.dissoc_in( \u003cem style=\"font-weight:400\"\u003em, pv\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nNested associative map key-\u003eval remover for [Pyrsistent](https://github.com/tobgu/pyrsistent). Returns a new map with dissociated changes, as `pyrsistent.PMap`.\n\nArgs:\n* `m` map to transform, as `pyrsistent.PMap`.\n* `pv` a path vector of keys indicating location of desired dissoc, as `pyrsistent.PVector` or `list`\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003enotify\u003c/a\u003e.filterkv( \u003cem style=\"font-weight:400\"\u003em, f, *a\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nTrivial associative map filter. Returns a new map with filtered changes, as `pyrsistent.PMap`.\n\nArgs:\n* `m` map to filter, as `pyrsistent.PMap`.\n* `f` filter function that accepts at least a key and a value as args, as `callable`.\n* `*a` optional additional args to pass to filter function, as `whatever!`\n\n\u003chr style=\"height:1px\"\u003e\n\n#### \u003cmark\u003e\u003cstrong\u003e\u003ca style=\"font-weight:400\"\u003enotify\u003c/a\u003e.as_async( \u003cem style=\"font-weight:400\"\u003ef, *a\u003c/em\u003e )\u003c/strong\u003e\u003c/mark\u003e\nRuns asynchronous and/or blocking functions in a new asyncio loop, as a task, in a thread. Designed to be called from a synchronous context. Returns `concurrent.futures.Future`.\n\nArgs:\n* `f` function to run in asyncio loop, as `callable`.\n* `*a` optional args to function `f` (e.g. a blocking function call that might produce a result in the future), as `whatever!`\n\n\u003chr style=\"height:1px\"\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenhowell%2Fpgnotifier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbenhowell%2Fpgnotifier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenhowell%2Fpgnotifier/lists"}