Skip to content
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-17451: raise when columnviews access undefined keys #431

Merged
merged 4 commits into from Feb 4, 2019

Conversation

jdswinbank
Copy link
Contributor

No description provided.

Copy link
Contributor

@parejkoj parejkoj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of questions and comments.

Two broader points:

  1. I would rebase squash the tests with the new C++ code, since they clearly go together.

  2. It may be out of scope, but I feel like testColumnView and _testFluxSlot have too much in them right now: it's hard to keep track of what is going on and what should or shouldn't be available at any given point. It may be too annoying given all the other code to manage the catalogs, but I wonder if you couldn't put them in their own test case, so that the success/failure condition is more obvious?

if (!key.isValid()) {
throw LSST_EXCEPT(
pex::exceptions::LogicError,
"Key is not valid (if this is a SourceCatalog, make sure slot aliases have been set up).");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why SourceCatalog here? Can slots not be set on SimpleCatalogs? What other types of catalogs can or cannot have slots?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slots are for SourceTables (or Catalogs) only (see e.g. https://github.com/lsst/afw/blob/master/include/lsst/afw/table/slots.h#L24).

for keyType in ["Angle", "ArrayB", "ArrayD", "ArrayF", "ArrayI",
"ArrayU", "B", "D", "F", "Flag", "I", "L", "U"]:
# Default-constructed key is invalid
invalidKey = getattr(lsst.afw.table, f"Key{keyType}")()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat use of format strings. I need to use those more.

# Default-constructed key is invalid
invalidKey = getattr(lsst.afw.table, f"Key{keyType}")()
self.assertFalse(invalidKey.isValid())
self.assertRaises(lsst.pex.exceptions.LogicError, catalog.get, invalidKey)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the context manager version easier to understand the intent:

with self.assertRaises(LogicError):
    catalog.get(invalidKey)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is just taste. Personally, I prefer the non-context-manager version when testing the result of a simple function call; the context manager is obviously better when dealing with more involved logic.

Copy link
Member

@timj timj Jan 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The testing guide prefers the context manager. Currently about 90% of the LSST code base complies with that statement (and I definitely prefer the context manage for code readability).

https://developer.lsst.io/python/testing.html?highlight=assertraises

@@ -69,6 +69,11 @@ std::shared_ptr<BaseTable> BaseColumnView::getTable() const { return _impl->tabl

template <typename T>
typename ndarray::ArrayRef<T, 1> const BaseColumnView::operator[](Key<T> const &key) const {
if (!key.isValid()) {
throw LSST_EXCEPT(
pex::exceptions::LogicError,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this raise LogicError or KeyError?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reckon LogicError, for consistency with the behaviour when accessing an invalid key on a single record. I was actually surprised that was a LogicError, but I think changing it on this ticket is out of scope.

@@ -639,7 +643,8 @@ def _testFluxSlot(self, slotName):
type=np.float64, doc="flux uncertainty")
flagKey = schema.addField("%s_flag" % (baseName,),
type="Flag", doc="flux flag")
table = lsst.afw.table.SourceTable.make(schema)
catalog = lsst.afw.table.SourceCatalog(schema)
table = catalog.table
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish someone would explain to me the difference between an Table and a Catalog...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roughy speaking (and I'm sure Jim or somebody else who knows better will be along to correct me in a moment):

  • Tables are (confusingly named) record factories.
  • Catalogs are containers of records.

In this particular case, we were previously only testing access to slots on individual records, so we only needed a table (a factory to create those records). I extended the test to test that the slot worked properly on a catalog (ie, a collection of records) too; obviously, that means we need to create the catalog for testing.

self.catalog.table.schema.getAliasMap().erase("slot_Centroid")
self.catalog.table.schema.getAliasMap().erase("slot_Shape")
for quantity in ["X", "Y", "Ixx", "Iyy", "Ixy"]:
self.assertRaises(lsst.pex.exceptions.LogicError, getattr(self.catalog, f"get{quantity}"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again with the with. Please add a comment above this explaining what this test is doing: it took me a bit to figure it out.

# And we should be able to delete the slot, breaking the mapping.
table.schema.getAliasMap().erase("slot_%s" % (slotName,))
self.assertFalse(getattr(table, "get%sSlot" % (slotName,))().isValid())
self.assertNotEqual(getattr(table, "get%sSlot" % (slotName,))().getMeasKey(), instFluxKey)
self.assertNotEqual(getattr(table, "get%sSlot" % (slotName,))().getErrKey(), errKey)
self.assertNotEqual(getattr(table, "get%sSlot" % (slotName,))().getFlagKey(), flagKey)

with self.assertRaises(lsst.pex.exceptions.LogicError):
getattr(catalog, f"get{instFluxName}")()
with self.assertRaises(lsst.pex.exceptions.LogicError):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should these two raise? I would have thought they would work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are referring to keys which are defined as part of the slot. When the slot is erased (at line 675, above), all the keys defined as part of it are invalidated. Accessing via those invalid keys raises.

I'll add a comment to that effect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants