{"action":"created","comment":{"url":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/comments/200728379","pull_request_review_id":135105749,"id":200728379,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMDcyODM3OQ==","diff_hunk":"@@ -24,23 +26,140 @@ class Permission:\n     A permission level\n     \"\"\"\n \n-    def __init__(self, level: int, vhost: str,\n+    def __init__(self, level: int, vhosts: Set[str],\n                  deny_message: str = \"Access denied.\"):\n         \"\"\"\n-        Permission required to execute a command\n-        :param level: Relative permissions level\n-        :param vhost: associated vhost\n-        :param deny_message: message to display if user level < level required\n-        :return:\n+        creates a representation of a permission level required to execute an IRC command\n+\n+        Args:\n+            level (Permission): required Permission level\n+            vhosts (Set[str]): set of vhost strings that fall under this permission level\n+            deny_message (str): message displayed on message to display if user level < level\n+                required\n         \"\"\"\n+\n         log.debug(f\"Created new Permission object with permission {level}\")\n         self._level = level\n-        self._vhost = vhost\n+        self._vhosts = vhosts\n         self._denied_message = deny_message\n \n-    level = property(lambda self: self._level)\n-    vhost = property(lambda self: self._vhost)\n-    denied_message = property(lambda self: self._denied_message)\n+        _by_vhost.update({vhost: self for vhost in self._vhosts})\n+\n+    @property\n+    def level(self) -> int:\n+        \"\"\"\n+        Permission level\n+\n+        Returns:\n+            int\n+        \"\"\"\n+        return self._level\n+\n+    @property\n+    def vhosts(self) -> Set[str]:\n+        \"\"\"\n+        Registered vhosts that fall under this permission level\n+\n+        Returns:\n+            List[str]: list of registered vhosts\n+        \"\"\"\n+        return self._vhosts\n+\n+    @vhosts.setter\n+    def vhosts(self, value: Set[str]) -> None:\n+        \"\"\"\n+        Updates the registered vhosts for this permission object\n+\n+        This also has the side effect of updating the _by_vhost bindings for this object.\n+\n+        - Items removed from `vhosts` are removed from _by_vhost and\n+        - Items that are not in `vhosts` already are added to `_by_vhost`\n+\n+        Args:\n+            value (List[str]): list of vhosts\n+\n+        Returns:\n+            None\n+        \"\"\"\n+        if not isinstance(value, set):\n+            raise TypeError(f\"expected list got {type(value)}\")\n+\n+        # determine which items have been removed\n+        removed = self.vhosts - value\n+\n+        # determine which items are new\n+        added = value - self.vhosts\n+\n+        # recompute _by_vhost to exclude removed vhosts we have removed\n+        # ( as there is no bulk-remove method, this avoids a for loop and some function calls )\n+        all_vhosts = {vhost: permission for vhost, permission in _by_vhost.items() if\n+                      vhost not in removed}\n+\n+        # create a dict of new vhosts to register\n+        new_vhosts = {vhost: self for vhost in added}","path":"Modules/permissions.py","position":95,"original_position":95,"commit_id":"2e1f3da17c86582f987ab9fbb88e4572bd41e97b","original_commit_id":"2e1f3da17c86582f987ab9fbb88e4572bd41e97b","user":{"login":"theunkn0wn1","id":3110986,"node_id":"MDQ6VXNlcjMxMTA5ODY=","avatar_url":"https://avatars1.githubusercontent.com/u/3110986?v=4","gravatar_id":"","url":"https://api.github.com/users/theunkn0wn1","html_url":"https://github.com/theunkn0wn1","followers_url":"https://api.github.com/users/theunkn0wn1/followers","following_url":"https://api.github.com/users/theunkn0wn1/following{/other_user}","gists_url":"https://api.github.com/users/theunkn0wn1/gists{/gist_id}","starred_url":"https://api.github.com/users/theunkn0wn1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/theunkn0wn1/subscriptions","organizations_url":"https://api.github.com/users/theunkn0wn1/orgs","repos_url":"https://api.github.com/users/theunkn0wn1/repos","events_url":"https://api.github.com/users/theunkn0wn1/events{/privacy}","received_events_url":"https://api.github.com/users/theunkn0wn1/received_events","type":"User","site_admin":false},"body":"_by_vhost is a dict, and you appear to be suggesting a tupple comprehension? \r\n\r\nat any rate i think it is desirable to keep the dict comprehension as its own step.","created_at":"2018-07-06T17:58:31Z","updated_at":"2018-07-06T17:58:31Z","html_url":"https://github.com/FuelRats/pipsqueak3/pull/46#discussion_r200728379","pull_request_url":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/46","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/comments/200728379"},"html":{"href":"https://github.com/FuelRats/pipsqueak3/pull/46#discussion_r200728379"},"pull_request":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/46"}},"in_reply_to_id":199559070},"pull_request":{"url":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/46","id":198401710,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk4NDAxNzEw","html_url":"https://github.com/FuelRats/pipsqueak3/pull/46","diff_url":"https://github.com/FuelRats/pipsqueak3/pull/46.diff","patch_url":"https://github.com/FuelRats/pipsqueak3/pull/46.patch","issue_url":"https://api.github.com/repos/FuelRats/pipsqueak3/issues/46","number":46,"state":"open","locked":false,"title":"SPARK-21: Configurable Permissions","user":{"login":"theunkn0wn1","id":3110986,"node_id":"MDQ6VXNlcjMxMTA5ODY=","avatar_url":"https://avatars1.githubusercontent.com/u/3110986?v=4","gravatar_id":"","url":"https://api.github.com/users/theunkn0wn1","html_url":"https://github.com/theunkn0wn1","followers_url":"https://api.github.com/users/theunkn0wn1/followers","following_url":"https://api.github.com/users/theunkn0wn1/following{/other_user}","gists_url":"https://api.github.com/users/theunkn0wn1/gists{/gist_id}","starred_url":"https://api.github.com/users/theunkn0wn1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/theunkn0wn1/subscriptions","organizations_url":"https://api.github.com/users/theunkn0wn1/orgs","repos_url":"https://api.github.com/users/theunkn0wn1/repos","events_url":"https://api.github.com/users/theunkn0wn1/events{/privacy}","received_events_url":"https://api.github.com/users/theunkn0wn1/received_events","type":"User","site_admin":false},"body":"This PR implements configurable permission vhosts as described in SPARK-21. \n\n","created_at":"2018-06-29T19:14:35Z","updated_at":"2018-07-06T17:58:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"55d5ee2d6139b00d5996512113925243fd8ed00b","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/46/commits","review_comments_url":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/46/comments","review_comment_url":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/comments{/number}","comments_url":"https://api.github.com/repos/FuelRats/pipsqueak3/issues/46/comments","statuses_url":"https://api.github.com/repos/FuelRats/pipsqueak3/statuses/2e1f3da17c86582f987ab9fbb88e4572bd41e97b","head":{"label":"FuelRats:feature/SPARK-21","ref":"feature/SPARK-21","sha":"2e1f3da17c86582f987ab9fbb88e4572bd41e97b","user":{"login":"FuelRats","id":15741722,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1NzQxNzIy","avatar_url":"https://avatars3.githubusercontent.com/u/15741722?v=4","gravatar_id":"","url":"https://api.github.com/users/FuelRats","html_url":"https://github.com/FuelRats","followers_url":"https://api.github.com/users/FuelRats/followers","following_url":"https://api.github.com/users/FuelRats/following{/other_user}","gists_url":"https://api.github.com/users/FuelRats/gists{/gist_id}","starred_url":"https://api.github.com/users/FuelRats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/FuelRats/subscriptions","organizations_url":"https://api.github.com/users/FuelRats/orgs","repos_url":"https://api.github.com/users/FuelRats/repos","events_url":"https://api.github.com/users/FuelRats/events{/privacy}","received_events_url":"https://api.github.com/users/FuelRats/received_events","type":"Organization","site_admin":false},"repo":{"id":124962472,"node_id":"MDEwOlJlcG9zaXRvcnkxMjQ5NjI0NzI=","name":"pipsqueak3","full_name":"FuelRats/pipsqueak3","owner":{"login":"FuelRats","id":15741722,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1NzQxNzIy","avatar_url":"https://avatars3.githubusercontent.com/u/15741722?v=4","gravatar_id":"","url":"https://api.github.com/users/FuelRats","html_url":"https://github.com/FuelRats","followers_url":"https://api.github.com/users/FuelRats/followers","following_url":"https://api.github.com/users/FuelRats/following{/other_user}","gists_url":"https://api.github.com/users/FuelRats/gists{/gist_id}","starred_url":"https://api.github.com/users/FuelRats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/FuelRats/subscriptions","organizations_url":"https://api.github.com/users/FuelRats/orgs","repos_url":"https://api.github.com/users/FuelRats/repos","events_url":"https://api.github.com/users/FuelRats/events{/privacy}","received_events_url":"https://api.github.com/users/FuelRats/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/FuelRats/pipsqueak3","description":"Pipsqueak3, aka Spark aka Mechasqueak ","fork":false,"url":"https://api.github.com/repos/FuelRats/pipsqueak3","forks_url":"https://api.github.com/repos/FuelRats/pipsqueak3/forks","keys_url":"https://api.github.com/repos/FuelRats/pipsqueak3/keys{/key_id}","collaborators_url":"https://api.github.com/repos/FuelRats/pipsqueak3/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/FuelRats/pipsqueak3/teams","hooks_url":"https://api.github.com/repos/FuelRats/pipsqueak3/hooks","issue_events_url":"https://api.github.com/repos/FuelRats/pipsqueak3/issues/events{/number}","events_url":"https://api.github.com/repos/FuelRats/pipsqueak3/events","assignees_url":"https://api.github.com/repos/FuelRats/pipsqueak3/assignees{/user}","branches_url":"https://api.github.com/repos/FuelRats/pipsqueak3/branches{/branch}","tags_url":"https://api.github.com/repos/FuelRats/pipsqueak3/tags","blobs_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/refs{/sha}","trees_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/trees{/sha}","statuses_url":"https://api.github.com/repos/FuelRats/pipsqueak3/statuses/{sha}","languages_url":"https://api.github.com/repos/FuelRats/pipsqueak3/languages","stargazers_url":"https://api.github.com/repos/FuelRats/pipsqueak3/stargazers","contributors_url":"https://api.github.com/repos/FuelRats/pipsqueak3/contributors","subscribers_url":"https://api.github.com/repos/FuelRats/pipsqueak3/subscribers","subscription_url":"https://api.github.com/repos/FuelRats/pipsqueak3/subscription","commits_url":"https://api.github.com/repos/FuelRats/pipsqueak3/commits{/sha}","git_commits_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/commits{/sha}","comments_url":"https://api.github.com/repos/FuelRats/pipsqueak3/comments{/number}","issue_comment_url":"https://api.github.com/repos/FuelRats/pipsqueak3/issues/comments{/number}","contents_url":"https://api.github.com/repos/FuelRats/pipsqueak3/contents/{+path}","compare_url":"https://api.github.com/repos/FuelRats/pipsqueak3/compare/{base}...{head}","merges_url":"https://api.github.com/repos/FuelRats/pipsqueak3/merges","archive_url":"https://api.github.com/repos/FuelRats/pipsqueak3/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/FuelRats/pipsqueak3/downloads","issues_url":"https://api.github.com/repos/FuelRats/pipsqueak3/issues{/number}","pulls_url":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls{/number}","milestones_url":"https://api.github.com/repos/FuelRats/pipsqueak3/milestones{/number}","notifications_url":"https://api.github.com/repos/FuelRats/pipsqueak3/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/FuelRats/pipsqueak3/labels{/name}","releases_url":"https://api.github.com/repos/FuelRats/pipsqueak3/releases{/id}","deployments_url":"https://api.github.com/repos/FuelRats/pipsqueak3/deployments","created_at":"2018-03-12T23:07:06Z","updated_at":"2018-07-01T20:31:49Z","pushed_at":"2018-07-05T16:55:16Z","git_url":"git://github.com/FuelRats/pipsqueak3.git","ssh_url":"git@github.com:FuelRats/pipsqueak3.git","clone_url":"https://github.com/FuelRats/pipsqueak3.git","svn_url":"https://github.com/FuelRats/pipsqueak3","homepage":"","size":649,"stargazers_count":5,"watchers_count":5,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"archived":false,"open_issues_count":7,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause","node_id":"MDc6TGljZW5zZTU="},"forks":5,"open_issues":7,"watchers":5,"default_branch":"develop"}},"base":{"label":"FuelRats:develop","ref":"develop","sha":"9e25b086f36841c785548af52398cf4465a13ca2","user":{"login":"FuelRats","id":15741722,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1NzQxNzIy","avatar_url":"https://avatars3.githubusercontent.com/u/15741722?v=4","gravatar_id":"","url":"https://api.github.com/users/FuelRats","html_url":"https://github.com/FuelRats","followers_url":"https://api.github.com/users/FuelRats/followers","following_url":"https://api.github.com/users/FuelRats/following{/other_user}","gists_url":"https://api.github.com/users/FuelRats/gists{/gist_id}","starred_url":"https://api.github.com/users/FuelRats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/FuelRats/subscriptions","organizations_url":"https://api.github.com/users/FuelRats/orgs","repos_url":"https://api.github.com/users/FuelRats/repos","events_url":"https://api.github.com/users/FuelRats/events{/privacy}","received_events_url":"https://api.github.com/users/FuelRats/received_events","type":"Organization","site_admin":false},"repo":{"id":124962472,"node_id":"MDEwOlJlcG9zaXRvcnkxMjQ5NjI0NzI=","name":"pipsqueak3","full_name":"FuelRats/pipsqueak3","owner":{"login":"FuelRats","id":15741722,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1NzQxNzIy","avatar_url":"https://avatars3.githubusercontent.com/u/15741722?v=4","gravatar_id":"","url":"https://api.github.com/users/FuelRats","html_url":"https://github.com/FuelRats","followers_url":"https://api.github.com/users/FuelRats/followers","following_url":"https://api.github.com/users/FuelRats/following{/other_user}","gists_url":"https://api.github.com/users/FuelRats/gists{/gist_id}","starred_url":"https://api.github.com/users/FuelRats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/FuelRats/subscriptions","organizations_url":"https://api.github.com/users/FuelRats/orgs","repos_url":"https://api.github.com/users/FuelRats/repos","events_url":"https://api.github.com/users/FuelRats/events{/privacy}","received_events_url":"https://api.github.com/users/FuelRats/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/FuelRats/pipsqueak3","description":"Pipsqueak3, aka Spark aka Mechasqueak ","fork":false,"url":"https://api.github.com/repos/FuelRats/pipsqueak3","forks_url":"https://api.github.com/repos/FuelRats/pipsqueak3/forks","keys_url":"https://api.github.com/repos/FuelRats/pipsqueak3/keys{/key_id}","collaborators_url":"https://api.github.com/repos/FuelRats/pipsqueak3/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/FuelRats/pipsqueak3/teams","hooks_url":"https://api.github.com/repos/FuelRats/pipsqueak3/hooks","issue_events_url":"https://api.github.com/repos/FuelRats/pipsqueak3/issues/events{/number}","events_url":"https://api.github.com/repos/FuelRats/pipsqueak3/events","assignees_url":"https://api.github.com/repos/FuelRats/pipsqueak3/assignees{/user}","branches_url":"https://api.github.com/repos/FuelRats/pipsqueak3/branches{/branch}","tags_url":"https://api.github.com/repos/FuelRats/pipsqueak3/tags","blobs_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/refs{/sha}","trees_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/trees{/sha}","statuses_url":"https://api.github.com/repos/FuelRats/pipsqueak3/statuses/{sha}","languages_url":"https://api.github.com/repos/FuelRats/pipsqueak3/languages","stargazers_url":"https://api.github.com/repos/FuelRats/pipsqueak3/stargazers","contributors_url":"https://api.github.com/repos/FuelRats/pipsqueak3/contributors","subscribers_url":"https://api.github.com/repos/FuelRats/pipsqueak3/subscribers","subscription_url":"https://api.github.com/repos/FuelRats/pipsqueak3/subscription","commits_url":"https://api.github.com/repos/FuelRats/pipsqueak3/commits{/sha}","git_commits_url":"https://api.github.com/repos/FuelRats/pipsqueak3/git/commits{/sha}","comments_url":"https://api.github.com/repos/FuelRats/pipsqueak3/comments{/number}","issue_comment_url":"https://api.github.com/repos/FuelRats/pipsqueak3/issues/comments{/number}","contents_url":"https://api.github.com/repos/FuelRats/pipsqueak3/contents/{+path}","compare_url":"https://api.github.com/repos/FuelRats/pipsqueak3/compare/{base}...{head}","merges_url":"https://api.github.com/repos/FuelRats/pipsqueak3/merges","archive_url":"https://api.github.com/repos/FuelRats/pipsqueak3/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/FuelRats/pipsqueak3/downloads","issues_url":"https://api.github.com/repos/FuelRats/pipsqueak3/issues{/number}","pulls_url":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls{/number}","milestones_url":"https://api.github.com/repos/FuelRats/pipsqueak3/milestones{/number}","notifications_url":"https://api.github.com/repos/FuelRats/pipsqueak3/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/FuelRats/pipsqueak3/labels{/name}","releases_url":"https://api.github.com/repos/FuelRats/pipsqueak3/releases{/id}","deployments_url":"https://api.github.com/repos/FuelRats/pipsqueak3/deployments","created_at":"2018-03-12T23:07:06Z","updated_at":"2018-07-01T20:31:49Z","pushed_at":"2018-07-05T16:55:16Z","git_url":"git://github.com/FuelRats/pipsqueak3.git","ssh_url":"git@github.com:FuelRats/pipsqueak3.git","clone_url":"https://github.com/FuelRats/pipsqueak3.git","svn_url":"https://github.com/FuelRats/pipsqueak3","homepage":"","size":649,"stargazers_count":5,"watchers_count":5,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"archived":false,"open_issues_count":7,"license":{"key":"bsd-3-clause","name":"BSD 3-Clause \"New\" or \"Revised\" License","spdx_id":"BSD-3-Clause","url":"https://api.github.com/licenses/bsd-3-clause","node_id":"MDc6TGljZW5zZTU="},"forks":5,"open_issues":7,"watchers":5,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/46"},"html":{"href":"https://github.com/FuelRats/pipsqueak3/pull/46"},"issue":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/issues/46"},"comments":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/issues/46/comments"},"review_comments":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/46/comments"},"review_comment":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/pulls/46/commits"},"statuses":{"href":"https://api.github.com/repos/FuelRats/pipsqueak3/statuses/2e1f3da17c86582f987ab9fbb88e4572bd41e97b"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"theunkn0wn1"}}