{"action":"created","comment":{"url":"https://api.github.com/repos/hammerlab/varcode/pulls/comments/72810467","id":72810467,"diff_hunk":"@@ -16,39 +16,130 @@\n import os.path\n from collections import defaultdict\n \n-class Collection(object):\n+from typechecks import require_iterable_of\n+\n+from serializable import Serializable\n+\n+\n+class Collection(Serializable):\n     \"\"\"\n     Methods shared by EffectCollection and VariantCollection.\n     \"\"\"\n \n     def __init__(\n             self,\n             elements,\n-            path=None,\n+            element_type=None,\n             distinct=False,\n-            sort_key=None):\n+            sort_key=None,\n+            source_to_metadata_dict={}):\n+        \"\"\"\n+        Parameters\n+        ----------\n+        elements : list\n+            Collection of any class which  is compatible with the sort key\n+\n+        element_type : type\n+            Expected type for each element.\n+\n+        distinct : bool\n+            Only keep distinct entries or allow duplicates.\n+\n+        sort_key : fn\n+            Function which maps each element to a sorting criterion.\n+\n+        source_to_metadata_dict : dict\n+            Dictionary mapping sources names (most often file paths) to\n+            dictionaries from each element, each of which has a dictionary of\n+            metadata attributes. This nested dictionary has a type signature\n+            of source->element->attribute-value.\n+        \"\"\"\n+        if element_type is None:\n+            # attempt to infer element type if none is explicitly given\n+            types = set(type(x) for x in elements)\n+            if len(types) != 1:\n+                raise ValueError(\n+                    \"Could not determine unique type for elements of %s\" % elements)\n+            element_type = list(types)[0]\n+        else:\n+            require_iterable_of(elements, element_type)\n+\n         self.distinct = distinct\n         if distinct:\n             elements = set(elements)\n+        self.sort_key = sort_key\n         self.elements = sorted(elements, key=sort_key)\n-        self.path = path\n-        if path:\n-            # get the filename without any directory prefix\n-            self.filename = os.path.split(path)[1]\n-        else:\n-            self.filename = None\n+        self.source_to_metadata_dict = source_to_metadata_dict\n+\n+    def to_dict(self):\n+        return dict(\n+            elements=self.elements,\n+            distinct=self.distinct,\n+            sort_key=self.sort_key,\n+            source_to_metadata_dict=self.source_to_metadata_dict)\n+\n+    @property\n+    def sources(self):\n+        return set(self.source_to_metadata_dict.keys())\n+\n+    @property\n+    def metadata(self):\n+        \"\"\"\n+        The most common usage of a VariantCollection is loading a single VCF,\n+        in which case it's annoying to have to always specify that path\n+        when accessing metadata fields. This property is meant to both maintain\n+        backward compatibility with old versions of Varcode and make the common\n+        case easier.\n+        \"\"\"\n+        return self.source_to_metadata_dict[self.source]\n+\n+    @property\n+    def source(self):\n+        \"\"\"\n+        Returns the single source name for a variant collection if it is unique,\n+        otherwise raises an error.\n+        \"\"\"\n+        if len(self.sources) == 0:\n+            raise ValueError(\"No source associated with %s\" % self.__class__.__name__)\n+        elif len(self.sources) > 1:\n+            raise ValueError(\"Multiple sources for %s\" % self.__class__.__name__)\n+        return list(self.sources)[0]\n+\n+    @property\n+    def path(self):\n+        \"\"\"\n+        Alternative name for VariantCollection.source maintained for backward\n+        compatibility.\n+        \"\"\"\n+        return self.source\n+\n+    @property\n+    def filenames(self):\n+        \"\"\"\n+        Assuming sources are paths to VCF or MAF files, trim their directory\n+        path and return just the file names.\n+        \"\"\"\n+        return [os.path.split(source)[1] for source in self.sources if source]","path":"varcode/collection.py","position":116,"original_position":116,"commit_id":"c91dae467041cc7485b76c47680fd59ffa4714c9","original_commit_id":"c91dae467041cc7485b76c47680fd59ffa4714c9","user":{"login":"arahuja","id":455755,"avatar_url":"https://avatars.githubusercontent.com/u/455755?v=3","gravatar_id":"","url":"https://api.github.com/users/arahuja","html_url":"https://github.com/arahuja","followers_url":"https://api.github.com/users/arahuja/followers","following_url":"https://api.github.com/users/arahuja/following{/other_user}","gists_url":"https://api.github.com/users/arahuja/gists{/gist_id}","starred_url":"https://api.github.com/users/arahuja/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/arahuja/subscriptions","organizations_url":"https://api.github.com/users/arahuja/orgs","repos_url":"https://api.github.com/users/arahuja/repos","events_url":"https://api.github.com/users/arahuja/events{/privacy}","received_events_url":"https://api.github.com/users/arahuja/received_events","type":"User","site_admin":false},"body":"Is this the same as `os.basename`?","created_at":"2016-07-29T15:24:38Z","updated_at":"2016-07-29T15:24:38Z","html_url":"https://github.com/hammerlab/varcode/pull/161#discussion_r72810467","pull_request_url":"https://api.github.com/repos/hammerlab/varcode/pulls/161","_links":{"self":{"href":"https://api.github.com/repos/hammerlab/varcode/pulls/comments/72810467"},"html":{"href":"https://github.com/hammerlab/varcode/pull/161#discussion_r72810467"},"pull_request":{"href":"https://api.github.com/repos/hammerlab/varcode/pulls/161"}}},"pull_request":{"url":"https://api.github.com/repos/hammerlab/varcode/pulls/161","id":78902954,"html_url":"https://github.com/hammerlab/varcode/pull/161","diff_url":"https://github.com/hammerlab/varcode/pull/161.diff","patch_url":"https://github.com/hammerlab/varcode/pull/161.patch","issue_url":"https://api.github.com/repos/hammerlab/varcode/issues/161","number":161,"state":"open","locked":false,"title":"Commandline interface, simplified serialization, merging VariantCollections","user":{"login":"iskandr","id":48441,"avatar_url":"https://avatars.githubusercontent.com/u/48441?v=3","gravatar_id":"","url":"https://api.github.com/users/iskandr","html_url":"https://github.com/iskandr","followers_url":"https://api.github.com/users/iskandr/followers","following_url":"https://api.github.com/users/iskandr/following{/other_user}","gists_url":"https://api.github.com/users/iskandr/gists{/gist_id}","starred_url":"https://api.github.com/users/iskandr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iskandr/subscriptions","organizations_url":"https://api.github.com/users/iskandr/orgs","repos_url":"https://api.github.com/users/iskandr/repos","events_url":"https://api.github.com/users/iskandr/events{/privacy}","received_events_url":"https://api.github.com/users/iskandr/received_events","type":"User","site_admin":false},"body":"* Added `union` and `intersection` to `VariantCollection`. \r\n* We previously allowed one unique path and one metadata dictionary for each `VariantCollection`. This complicates merging collections since they can now come from multiple sources. I replaced `path` with a more general notion of 'source' and the tied sources to metadata by having them both come from a parameter called `sources_to_metadata_dict`.  I tried to maintain backward compatibility by providing helper properties like `source` and `metadata` for the most common situation when we get variants from a single source.\r\n* Simplified serialization to pickle and JSON by using the same `Serializable` base class as PyEnsembl. \r\n* Add `element_type` to `Collection`.\r\n* Made `varcode-variants` script which loads multiple VCF/MAF/manually specified variants, takes their union and can write out a combined collection.\r\n* Removed some cached properties which don't add much to performance but do eat up memory (general philosophy is now to only add caching around bottleneck methods, like those that talk to a database)\r\n\r\n<!-- Reviewable:start -->\r\n---\r\nThis change is [<img src=\"https://reviewable.io/review_button.svg\" height=\"34\" align=\"absmiddle\" alt=\"Reviewable\"/>](https://reviewable.io/reviews/hammerlab/varcode/161)\r\n<!-- Reviewable:end -->\r\n","created_at":"2016-07-26T18:39:39Z","updated_at":"2016-07-29T15:24:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9d2d94f65edf206a4f7685a9c23ab68e794f7f4a","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/hammerlab/varcode/pulls/161/commits","review_comments_url":"https://api.github.com/repos/hammerlab/varcode/pulls/161/comments","review_comment_url":"https://api.github.com/repos/hammerlab/varcode/pulls/comments{/number}","comments_url":"https://api.github.com/repos/hammerlab/varcode/issues/161/comments","statuses_url":"https://api.github.com/repos/hammerlab/varcode/statuses/c91dae467041cc7485b76c47680fd59ffa4714c9","head":{"label":"hammerlab:cli","ref":"cli","sha":"c91dae467041cc7485b76c47680fd59ffa4714c9","user":{"login":"hammerlab","id":6563873,"avatar_url":"https://avatars.githubusercontent.com/u/6563873?v=3","gravatar_id":"","url":"https://api.github.com/users/hammerlab","html_url":"https://github.com/hammerlab","followers_url":"https://api.github.com/users/hammerlab/followers","following_url":"https://api.github.com/users/hammerlab/following{/other_user}","gists_url":"https://api.github.com/users/hammerlab/gists{/gist_id}","starred_url":"https://api.github.com/users/hammerlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hammerlab/subscriptions","organizations_url":"https://api.github.com/users/hammerlab/orgs","repos_url":"https://api.github.com/users/hammerlab/repos","events_url":"https://api.github.com/users/hammerlab/events{/privacy}","received_events_url":"https://api.github.com/users/hammerlab/received_events","type":"Organization","site_admin":false},"repo":{"id":26663543,"name":"varcode","full_name":"hammerlab/varcode","owner":{"login":"hammerlab","id":6563873,"avatar_url":"https://avatars.githubusercontent.com/u/6563873?v=3","gravatar_id":"","url":"https://api.github.com/users/hammerlab","html_url":"https://github.com/hammerlab","followers_url":"https://api.github.com/users/hammerlab/followers","following_url":"https://api.github.com/users/hammerlab/following{/other_user}","gists_url":"https://api.github.com/users/hammerlab/gists{/gist_id}","starred_url":"https://api.github.com/users/hammerlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hammerlab/subscriptions","organizations_url":"https://api.github.com/users/hammerlab/orgs","repos_url":"https://api.github.com/users/hammerlab/repos","events_url":"https://api.github.com/users/hammerlab/events{/privacy}","received_events_url":"https://api.github.com/users/hammerlab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/hammerlab/varcode","description":"Library for manipulating genomic variants and predicting their effects","fork":false,"url":"https://api.github.com/repos/hammerlab/varcode","forks_url":"https://api.github.com/repos/hammerlab/varcode/forks","keys_url":"https://api.github.com/repos/hammerlab/varcode/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hammerlab/varcode/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hammerlab/varcode/teams","hooks_url":"https://api.github.com/repos/hammerlab/varcode/hooks","issue_events_url":"https://api.github.com/repos/hammerlab/varcode/issues/events{/number}","events_url":"https://api.github.com/repos/hammerlab/varcode/events","assignees_url":"https://api.github.com/repos/hammerlab/varcode/assignees{/user}","branches_url":"https://api.github.com/repos/hammerlab/varcode/branches{/branch}","tags_url":"https://api.github.com/repos/hammerlab/varcode/tags","blobs_url":"https://api.github.com/repos/hammerlab/varcode/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hammerlab/varcode/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hammerlab/varcode/git/refs{/sha}","trees_url":"https://api.github.com/repos/hammerlab/varcode/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hammerlab/varcode/statuses/{sha}","languages_url":"https://api.github.com/repos/hammerlab/varcode/languages","stargazers_url":"https://api.github.com/repos/hammerlab/varcode/stargazers","contributors_url":"https://api.github.com/repos/hammerlab/varcode/contributors","subscribers_url":"https://api.github.com/repos/hammerlab/varcode/subscribers","subscription_url":"https://api.github.com/repos/hammerlab/varcode/subscription","commits_url":"https://api.github.com/repos/hammerlab/varcode/commits{/sha}","git_commits_url":"https://api.github.com/repos/hammerlab/varcode/git/commits{/sha}","comments_url":"https://api.github.com/repos/hammerlab/varcode/comments{/number}","issue_comment_url":"https://api.github.com/repos/hammerlab/varcode/issues/comments{/number}","contents_url":"https://api.github.com/repos/hammerlab/varcode/contents/{+path}","compare_url":"https://api.github.com/repos/hammerlab/varcode/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hammerlab/varcode/merges","archive_url":"https://api.github.com/repos/hammerlab/varcode/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hammerlab/varcode/downloads","issues_url":"https://api.github.com/repos/hammerlab/varcode/issues{/number}","pulls_url":"https://api.github.com/repos/hammerlab/varcode/pulls{/number}","milestones_url":"https://api.github.com/repos/hammerlab/varcode/milestones{/number}","notifications_url":"https://api.github.com/repos/hammerlab/varcode/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hammerlab/varcode/labels{/name}","releases_url":"https://api.github.com/repos/hammerlab/varcode/releases{/id}","deployments_url":"https://api.github.com/repos/hammerlab/varcode/deployments","created_at":"2014-11-15T00:20:42Z","updated_at":"2016-06-15T22:13:00Z","pushed_at":"2016-07-27T23:53:49Z","git_url":"git://github.com/hammerlab/varcode.git","ssh_url":"git@github.com:hammerlab/varcode.git","clone_url":"https://github.com/hammerlab/varcode.git","svn_url":"https://github.com/hammerlab/varcode","homepage":"","size":4030,"stargazers_count":24,"watchers_count":24,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":32,"forks":2,"open_issues":32,"watchers":24,"default_branch":"master"}},"base":{"label":"hammerlab:master","ref":"master","sha":"78f789e7f09ff3e931414b477a051d3d72c040a5","user":{"login":"hammerlab","id":6563873,"avatar_url":"https://avatars.githubusercontent.com/u/6563873?v=3","gravatar_id":"","url":"https://api.github.com/users/hammerlab","html_url":"https://github.com/hammerlab","followers_url":"https://api.github.com/users/hammerlab/followers","following_url":"https://api.github.com/users/hammerlab/following{/other_user}","gists_url":"https://api.github.com/users/hammerlab/gists{/gist_id}","starred_url":"https://api.github.com/users/hammerlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hammerlab/subscriptions","organizations_url":"https://api.github.com/users/hammerlab/orgs","repos_url":"https://api.github.com/users/hammerlab/repos","events_url":"https://api.github.com/users/hammerlab/events{/privacy}","received_events_url":"https://api.github.com/users/hammerlab/received_events","type":"Organization","site_admin":false},"repo":{"id":26663543,"name":"varcode","full_name":"hammerlab/varcode","owner":{"login":"hammerlab","id":6563873,"avatar_url":"https://avatars.githubusercontent.com/u/6563873?v=3","gravatar_id":"","url":"https://api.github.com/users/hammerlab","html_url":"https://github.com/hammerlab","followers_url":"https://api.github.com/users/hammerlab/followers","following_url":"https://api.github.com/users/hammerlab/following{/other_user}","gists_url":"https://api.github.com/users/hammerlab/gists{/gist_id}","starred_url":"https://api.github.com/users/hammerlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hammerlab/subscriptions","organizations_url":"https://api.github.com/users/hammerlab/orgs","repos_url":"https://api.github.com/users/hammerlab/repos","events_url":"https://api.github.com/users/hammerlab/events{/privacy}","received_events_url":"https://api.github.com/users/hammerlab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/hammerlab/varcode","description":"Library for manipulating genomic variants and predicting their effects","fork":false,"url":"https://api.github.com/repos/hammerlab/varcode","forks_url":"https://api.github.com/repos/hammerlab/varcode/forks","keys_url":"https://api.github.com/repos/hammerlab/varcode/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hammerlab/varcode/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hammerlab/varcode/teams","hooks_url":"https://api.github.com/repos/hammerlab/varcode/hooks","issue_events_url":"https://api.github.com/repos/hammerlab/varcode/issues/events{/number}","events_url":"https://api.github.com/repos/hammerlab/varcode/events","assignees_url":"https://api.github.com/repos/hammerlab/varcode/assignees{/user}","branches_url":"https://api.github.com/repos/hammerlab/varcode/branches{/branch}","tags_url":"https://api.github.com/repos/hammerlab/varcode/tags","blobs_url":"https://api.github.com/repos/hammerlab/varcode/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hammerlab/varcode/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hammerlab/varcode/git/refs{/sha}","trees_url":"https://api.github.com/repos/hammerlab/varcode/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hammerlab/varcode/statuses/{sha}","languages_url":"https://api.github.com/repos/hammerlab/varcode/languages","stargazers_url":"https://api.github.com/repos/hammerlab/varcode/stargazers","contributors_url":"https://api.github.com/repos/hammerlab/varcode/contributors","subscribers_url":"https://api.github.com/repos/hammerlab/varcode/subscribers","subscription_url":"https://api.github.com/repos/hammerlab/varcode/subscription","commits_url":"https://api.github.com/repos/hammerlab/varcode/commits{/sha}","git_commits_url":"https://api.github.com/repos/hammerlab/varcode/git/commits{/sha}","comments_url":"https://api.github.com/repos/hammerlab/varcode/comments{/number}","issue_comment_url":"https://api.github.com/repos/hammerlab/varcode/issues/comments{/number}","contents_url":"https://api.github.com/repos/hammerlab/varcode/contents/{+path}","compare_url":"https://api.github.com/repos/hammerlab/varcode/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hammerlab/varcode/merges","archive_url":"https://api.github.com/repos/hammerlab/varcode/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hammerlab/varcode/downloads","issues_url":"https://api.github.com/repos/hammerlab/varcode/issues{/number}","pulls_url":"https://api.github.com/repos/hammerlab/varcode/pulls{/number}","milestones_url":"https://api.github.com/repos/hammerlab/varcode/milestones{/number}","notifications_url":"https://api.github.com/repos/hammerlab/varcode/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hammerlab/varcode/labels{/name}","releases_url":"https://api.github.com/repos/hammerlab/varcode/releases{/id}","deployments_url":"https://api.github.com/repos/hammerlab/varcode/deployments","created_at":"2014-11-15T00:20:42Z","updated_at":"2016-06-15T22:13:00Z","pushed_at":"2016-07-27T23:53:49Z","git_url":"git://github.com/hammerlab/varcode.git","ssh_url":"git@github.com:hammerlab/varcode.git","clone_url":"https://github.com/hammerlab/varcode.git","svn_url":"https://github.com/hammerlab/varcode","homepage":"","size":4030,"stargazers_count":24,"watchers_count":24,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":32,"forks":2,"open_issues":32,"watchers":24,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/hammerlab/varcode/pulls/161"},"html":{"href":"https://github.com/hammerlab/varcode/pull/161"},"issue":{"href":"https://api.github.com/repos/hammerlab/varcode/issues/161"},"comments":{"href":"https://api.github.com/repos/hammerlab/varcode/issues/161/comments"},"review_comments":{"href":"https://api.github.com/repos/hammerlab/varcode/pulls/161/comments"},"review_comment":{"href":"https://api.github.com/repos/hammerlab/varcode/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/hammerlab/varcode/pulls/161/commits"},"statuses":{"href":"https://api.github.com/repos/hammerlab/varcode/statuses/c91dae467041cc7485b76c47680fd59ffa4714c9"}}}}
{"actor":{"display_login":"arahuja"}}