{"action":"created","issue":{"url":"https://api.github.com/repos/biocore/scikit-bio/issues/1193","labels_url":"https://api.github.com/repos/biocore/scikit-bio/issues/1193/labels{/name}","comments_url":"https://api.github.com/repos/biocore/scikit-bio/issues/1193/comments","events_url":"https://api.github.com/repos/biocore/scikit-bio/issues/1193/events","html_url":"https://github.com/biocore/scikit-bio/pull/1193","id":118084901,"number":1193,"title":"Allow subclasses of TreeNode to be used","user":{"login":"terrycojones","id":132978,"avatar_url":"https://avatars.githubusercontent.com/u/132978?v=3","gravatar_id":"","url":"https://api.github.com/users/terrycojones","html_url":"https://github.com/terrycojones","followers_url":"https://api.github.com/users/terrycojones/followers","following_url":"https://api.github.com/users/terrycojones/following{/other_user}","gists_url":"https://api.github.com/users/terrycojones/gists{/gist_id}","starred_url":"https://api.github.com/users/terrycojones/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/terrycojones/subscriptions","organizations_url":"https://api.github.com/users/terrycojones/orgs","repos_url":"https://api.github.com/users/terrycojones/repos","events_url":"https://api.github.com/users/terrycojones/events{/privacy}","received_events_url":"https://api.github.com/users/terrycojones/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-11-20T17:13:21Z","updated_at":"2015-11-20T17:51:15Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/biocore/scikit-bio/pulls/1193","html_url":"https://github.com/biocore/scikit-bio/pull/1193","diff_url":"https://github.com/biocore/scikit-bio/pull/1193.diff","patch_url":"https://github.com/biocore/scikit-bio/pull/1193.patch"},"body":"I've just started using scikit-bio (thanks!) and ran into something a little inflexible that I think could be improved quite easily.\r\n\r\nI'd like to have my own `TreeNode` class so I can store attributes and methods on it. This issue has come up in various other guises, see e.g., #1117, #809, and #465.\r\n\r\nIf I can't use my own subclass, I need to keep per-node metadata somewhere else, and keep it up to date, etc. E.g., I could make a class, `MyClass`, that keeps a `TreeNode` instance (e.g., called `tree`) plus some other metadata. This is quite inconvenient and un-Pythonic. It means I need to call the extra methods of my class using things like\r\n\r\n```python\r\nmyClass = MyClass()\r\nfor node in myClass.tree.children:\r\n    if myClass.nodeSupport(node) > 0:\r\n        # pass\r\n```\r\n\r\nrather than the simpler approach in which I subclass `TreeNode` and add the methods and attributes I want.  The simpler approach also makes testing easier.\r\n\r\nAnyway, the usual way to do this is to pass around a class that is used to make new tree nodes, and have it default to the original simple base class (`TreeNode` in this case).\r\n\r\nI'm not proposing that this pull request gets merged at the moment, but would like to see what people think of the idea and the simple diff.  If this seems like a good direction, I can add some tests that subclass `TreeNode` and which pass a `tree_node_class` argument to `majority_rule`.\r\n\r\nThanks again for scikit-bio!"},"comment":{"url":"https://api.github.com/repos/biocore/scikit-bio/issues/comments/158473218","html_url":"https://github.com/biocore/scikit-bio/pull/1193#issuecomment-158473218","issue_url":"https://api.github.com/repos/biocore/scikit-bio/issues/1193","id":158473218,"user":{"login":"terrycojones","id":132978,"avatar_url":"https://avatars.githubusercontent.com/u/132978?v=3","gravatar_id":"","url":"https://api.github.com/users/terrycojones","html_url":"https://github.com/terrycojones","followers_url":"https://api.github.com/users/terrycojones/followers","following_url":"https://api.github.com/users/terrycojones/following{/other_user}","gists_url":"https://api.github.com/users/terrycojones/gists{/gist_id}","starred_url":"https://api.github.com/users/terrycojones/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/terrycojones/subscriptions","organizations_url":"https://api.github.com/users/terrycojones/orgs","repos_url":"https://api.github.com/users/terrycojones/repos","events_url":"https://api.github.com/users/terrycojones/events{/privacy}","received_events_url":"https://api.github.com/users/terrycojones/received_events","type":"User","site_admin":false},"created_at":"2015-11-20T17:51:15Z","updated_at":"2015-11-20T17:51:15Z","body":"Hi @wasade \r\n\r\nThanks. I can add attributes myself to `TreeNode` instances, but it's quite cumbersome in some cases. E.g., if I call a `TreeNode` method that alters the tree, I may need to walk the tree myself to see if I need to add/update my attributes on all nodes (some nodes may be new, some nodes may have different numbers of siblings or whatever, etc). Or if I want to change the behavior of any of the existing methods (even something simple, like `__str__`), it'd be a real pain. Adding something like `__eq__`, as several people seem to have wanted to do (perhaps in quite different ways, which can be done trivially via subclasses), is also hard. Of course these things can be done with additional (external) functions, but that's awkward too."}}