New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DM-7199: afwTable's .getX()/.getY() do not appear in dir() #238
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have a unittest for this? I'm not sure at what level to put it (since this is the base class for so many things), but it seems like this could be a bit fragile (I don't have any evidence for that, just vague feelings)?
Also, has anyone tried benchmarking it for one of our classes a ways down the hierarchy? set
is pretty fast, but I wonder if we have anything with enough __bases__
to matter?
@@ -283,6 +283,24 @@ def asAstropy(self, cls=None, copy=False, unviewable="copy"): | |||
) | |||
return cls(columns, meta=meta, copy=False) | |||
|
|||
def __dir__(self): | |||
# This custom dir is necessary due to the custom getattr below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a docstring instead of a comment?
result |= recursive_get_class_dir(subcls) | ||
result |= set(cls.__dict__.keys()) | ||
return result | ||
return sorted(set(dir(self.columns)) | set(dir(self.table)) | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know about the set operators (pipe for union, in this case). That's cool.
Separately, I think this return should be separated from the above by a line, since it's not part of that inner function.
result |= set(cls.__dict__.keys()) | ||
return result | ||
return sorted(set(dir(self.columns)) | set(dir(self.table)) | | ||
recursive_get_class_dir(type(self)) | set(self.__dict__.keys())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you just do set(self.__dict__)
at the end?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed so, at least in python 3. I'm not sure if this would work in python 2 though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right. Burned by py2 again.
''' | ||
result = set() | ||
if cls.__bases__: | ||
for subcls in cls.__bases__: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this works, but the use of __bases__
feels exceptionally clever.
Does the MRO matter here at all? Probably not, since it's all going into a set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the... MRO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. I don't think this matters, because it's all going into a set, and ultimately lands in a sorted list that excludes duplicates. And I choose to take "exceptionally clever" as a compliment, largely on Russell's behalf.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that you are often much more clever writing code than trying to understand it later. That was the nature of my comment.
I'm willing to write a unittest, but I also have no idea where it should live, or even what exactly it would test. Suggestions welcome. |
Meant to also say - Jenkins passed for py2, but not for py3, because of |
Re-run jenkins. That looks like one of the sporadic failures we've been getting. |
Oh good, Jenkins passed this time! |
I agree that a unit test is a good idea. I suggest using the test script you already have as the basis for a new test method in an existing test of SourceCatalog. Something like this:
Also, I would be tempted to move the special function definition up to the module level, to make sure it only gets declared once (I am not sure if Python is smart enough to realize that nothing in the function definition depends on variables local to the As to cleverness: the fact that Catalog overrides |
OK, that makes sense, I'm happy to add this test. When you say "move the special function definition up to the module level," do you mean just the custom I'm headed off on vacation for a week tonight and won't be able to get to this until I'm back. If you want to finish it without me, @r-owen, you are welcome to, but you certainly don't have to. |
The function I think might want to be moved is |
bf2cb27
to
6505879
Compare
I think this should be ready now. It turns out I ran Jenkins before the new test was actually doing anything, but it passes when I run it locally with pytest. I can run Jenkins again if you think it's necessary. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See further comments.
The thing I was worried about re:speed was exactly in an interactive environment: ipython/jupyter use dir()
to populate the auto-completion list. Might be worth copying some of your test code into a jupyter notebook, and typing catalog.[TAB]
and see if the list pops up quickly.
''' | ||
result = set() | ||
if cls.__bases__: | ||
for subcls in cls.__bases__: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that you are often much more clever writing code than trying to understand it later. That was the nature of my comment.
result |= set(cls.__dict__.keys()) | ||
return result | ||
return sorted(set(dir(self.columns)) | set(dir(self.table)) | | ||
recursive_get_class_dir(type(self)) | set(self.__dict__.keys())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right. Burned by py2 again.
tests/testDir.py
Outdated
attrNames = dir(catalog) | ||
desiredNames = set(['_columns', 'getX', 'asAstropy', 'hasPsfFluxSlot']) | ||
self.assertTrue(desiredNames.issubset(attrNames)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should have the MemoryTestCase here.
tests/testDir.py
Outdated
# Compare catalog attributes with those from various catalog subclasses | ||
attrNames = dir(catalog) | ||
desiredNames = set(['_columns', 'getX', 'asAstropy', 'hasPsfFluxSlot']) | ||
self.assertTrue(desiredNames.issubset(attrNames)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a reasonable way to test that dir(catalog)
contains those things. I'd suggest we also include getY
in the list. Anything else we should also include? It doesn't hurt to be comprehensive in this test.
|
No description provided.