-
Notifications
You must be signed in to change notification settings - Fork 80
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
Added a simple Python version of the Atlas #140
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.
Really nice addition! A few questions included. Also Is the pyatlas/pyatlas/autogen/__init__.py
empty file included on purpose?
Also: Maybe add a short description + link in the main readme?
# GNU and BSD sed have different "in-place" flag syntax | ||
if [ "$(uname)" == "Darwin" ]; | ||
then | ||
sed -i "" "s/version=.*/version=\"$atlas_version\",/" "$pyatlas_root_dir/setup.py" |
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.
Awesome!
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.
A bit of a hack but it works! Maintaining it is my problem anyway :)
load_method_to_call() | ||
|
||
|
||
class _PackedTagStore(object): |
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.
Are those included in the same file to make them "private"?
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.
It's not the fact that they are included in the same package, rather the leading _
character is what makes them private. You can see in the geometry
module that there are many classes defined there, none of which are private.
The reason I placed _PackedTagStore
and _IntegerDictionary
in the atlas
module is because they are only called from within that module, and they don't need to be exposed to the user for import or documentation.
return frozenset(relation_set) | ||
|
||
|
||
class Point(AtlasEntity): |
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.
Pretty cool flyweight implementation!
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 take no credit for this design. Copied straight from your PackedAtlas
:)
|
||
def _urshift32(to_shift, shift_amount): | ||
""" | ||
Perform a 32 bit unsigned right shift (drag in leading 0s). |
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.
Nice!
pyatlas/pyatlas/spatial_index.py
Outdated
immutable, so this method forces a rebuild of the entire tree. | ||
""" | ||
self.contents.append(entity) | ||
self._construct_tree_from_contents() |
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.
Would it make sense to have two methods, one called "add" and another one called "finishedAdding"? That way you do not build the rtree at every call?
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 suppose I could change the name to something different, just to make it more clear. I included an implementation of add
in RTree
to make the interface consistent across tree implementations, since the SpatialIndex.add
method simply calls add
on whatever its backing tree is. In the case that you have a SpatialIndex
backed by a QuadTree
, there is no forced tree rebuild.
The reason I implemented the RTree
this way (with the forced rebuild) is because the STR packed R-tree provided by GEOS (thru Shapely) is effectively immutable once it has been "built" (you can see what I mean by "built" by checking out this GEOS class, "building" occurs as a side effect of queries to the tree, see the query
method in the linked code ).
So effectively, the only way to add elements to the tree once it has been "built" is to rebuild the tree from scratch. However, this limitation does not apply when constructing the tree for the first time, which is why I provided the initial_entities
parameter in the constructor of the RTree
class.
Ideally, users will not be building their own RTrees
anyway. The Atlas
lazily constructs the spatial indices it needs at query time. However, I made the SpatialIndex
interface public in case someone really wants to extend the spatial capabilities of an Atlas
without necessarily modifying the Atlas
class itself. Using the provided interface, one could attach a custom SpatialIndex
with a custom subset of features to an arbitrary Atlas
.
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.
It would be awesome to add all this as a comment in that method!
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.
Haha sounds good, I'll clean this up to be a bit more concise and to the point.
from pyatlas.geometry import Rectangle | ||
|
||
|
||
class AtlasTest(unittest.TestCase): |
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.
If those tests fail, are they build breaking?
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.
Yes, failing unit tests cause the build to abort with a diagnostic detailing the failed test and the cause of the failure. It's very similar to the JUnit setup we have in Java Atlas.
Glad to get this thing started! Yes the |
I was wondering if it was ok to have it in the |
You have to, since the |
README.md
Outdated
@@ -160,6 +160,10 @@ final Atlas atlas2; | |||
new PackedAtlasCloner().cloneFrom(new MultiAtlas(atlas1, atlas2)).save(new File("/path/to/file.atlas")); | |||
``` | |||
|
|||
# PyAtlas | |||
|
|||
`Atlas` features a lightweight Python version of the core functionality. The `pyatlas` is available as a Python package from PyPI, but can also be built and installed locally. Check out the `pyatlas` subfolder and the `pyatlas/README.md` file for more information! |
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.
You could link it directly here using ... [Readme file](pyatlas/README.md) ...
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 ok let me add that. I did not realize you could do relative URLs.
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.
A couple questions, but looks really good! Thanks for the thorough tests.
""" | ||
Print a welcome message! | ||
""" | ||
print "Hello Atlas!" |
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.
Is this just a default global function to be replaced in future?
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.
Good question :) It's pretty much just there for the Getting Started
section of the README, which has the user call it to test that the package built correctly. In the future this module may have additional function definitions.
#!/usr/bin/env bash | ||
|
||
# THIS ENTIRE SCRIPT IS A MASSIVE HACK | ||
# THIS SHOULD REALLY BE DONE WITH GRADLE |
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.
amazing :)
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 really need to remove this comment... :P
self.assertEquals({atlas.point(3)}, test_results) | ||
|
||
test_results = atlas.points_at(geometry.location_with_degrees(38, -118)) | ||
self.assertEquals({atlas.point(1)}, test_results) |
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.
Have these been tested and verified against the Java version?
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 is no automatic verification, but I have tested it manually against the Java version with the help of a script not included in this PR. Based on my tests the query results are consistent. But more tests are always welcome!
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.
Really nice work!
return len(self.word_to_index) | ||
|
||
def word(self, index): | ||
# TODO this could throw a KeyError, how to handle? |
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.
Something to address or ignore for now?
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 changed the way that class is used internally, so I believe that comment is outdated now. Good catch.
See the readme under pyatlas/README.md for more information.
This PR modifies the Travis release process to publish a pyatlas distribution to PyPI.
Currently, the distribution is not GPG signed. It is possible to change this, if we feel it is necessary. However I do not believe PyPI requires it.