Skip to content

Commit 65f2c63

Browse files
committed
Merge pull request #18 from mattmakesmaps/development
Release 0.2.2
2 parents 4374a02 + a6ca0f0 commit 65f2c63

File tree

7 files changed

+73
-12
lines changed

7 files changed

+73
-12
lines changed

CHANGES.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
CHANGES
33
=======
44

5+
Release 0.2.2
6+
-------------
7+
8+
* Refactor geojson.py --> constructors.py
9+
* Documented duck type interface for constructor classes.
10+
* Updated README.txt to reflect new entry point.
11+
512
Release 0.2.1
613
-------------
714

README.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Listed below is the --help usage information.::
2020

2121
POST GeoJSON or TopoJSON features from PostGIS to a Github Gist.
2222

23-
Example usage: python pgsql2gist.py --host localhost --user matt tilestache \
23+
Example usage: pgsql2gist --host localhost --user matt tilestache \
2424
"SELECT name, ST_AsGeoJSON(geom) AS geometry FROM neighborhoods LIMIT 5;"
2525

2626
Current SELECT Statement Requirements:

pgsql2gist/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
from .gisthandler import GistAPIHandler
66
from .pgconn import PostGISConnection
77
from .cli import CLIInterface
8-
from .geojson import GeoJSONConstructor, OutOfBoundsError
8+
from .constructors import GeoJSONConstructor, TopoJSONConstructor, OutOfBoundsError

pgsql2gist/cli.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ def __init__(self):
1515
"""
1616
self.parser = argparse.ArgumentParser(add_help=False,
1717
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
18+
# Internal Attribute will be used to populate dictionary in get_args_dict() method.
19+
self._format = None
1820
# Build Parser
1921
self.setup()
2022

@@ -40,12 +42,14 @@ def setup(self):
4042

4143
def get_args_dict(self):
4244
"""
43-
Given an argparse parser object, wrap in a call to vars(), returning dictionary.
45+
Given an argparse parser object, wrap in a call to vars(), returning a dictionary of attributes.
4446
This method also calls the input validation method.
4547
"""
4648
args = self.parser.parse_args()
4749
args_dict = vars(args)
4850
if self._validate_args_dict(args_dict):
51+
# Expose internal _format attribute along with dictionary of arg parse attributes.
52+
args_dict["format"] = self._format
4953
return args_dict
5054

5155
def _validate_args_dict(self, args_dict):
@@ -67,16 +71,19 @@ def _validate_file_ext(self, args_dict):
6771
"""
6872
Validate that file extensions are either geojson or topojson.
6973
Required for data to render in mapping interface.
74+
75+
Set the class' _format attribute.
7076
"""
71-
valid_extensions = ['.geojson', 'topojson']
77+
valid_extensions = ['geojson', 'topojson']
7278
ext_is_valid = False
7379
for ext in valid_extensions:
7480
if args_dict['file'].endswith(ext):
81+
self._format = ext
7582
ext_is_valid = True
7683
if ext_is_valid:
7784
return True
7885
else:
79-
raise ValueError('File extension does not end in .geojson or .topojson')
86+
raise ValueError("File does not end in '.geojson' or '.topojson'. NOTE: Gist API is case-sensitive.")
8087

8188
def _validate_topojson_geojson_call(self, args_dict):
8289
"""

pgsql2gist/command_line.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"""
55
POST GeoJSON or TopoJSON features from PostGIS to a Github Gist.
66
7-
Example usage: python pgsql2gist.py --host localhost --user matt tilestache \
7+
Example usage: pgsql2gist --host localhost --user matt tilestache \
88
"SELECT name, ST_AsGeoJSON(geom) AS geometry FROM neighborhoods LIMIT 5;"
99
1010
Current SELECT Statement Requirements:
@@ -39,7 +39,7 @@
3939
# Import relevant modules from the pgsql2gist package.
4040
import time
4141
from psycopg2 import Error
42-
from pgsql2gist import GistAPIHandler, PostGISConnection, CLIInterface, GeoJSONConstructor
42+
from pgsql2gist import GistAPIHandler, PostGISConnection, CLIInterface, GeoJSONConstructor, TopoJSONConstructor
4343

4444

4545
def main():
@@ -58,8 +58,14 @@ def main():
5858
# Get results
5959
query_results = db.fetchall()
6060

61-
# Create GeoJSON Feature Collection
62-
features = GeoJSONConstructor(query_results, args["geom_col"]).encode()
61+
# Mapping of file extensions to constructor classes
62+
constructor_lookup = {'geojson': GeoJSONConstructor,
63+
'topojson': TopoJSONConstructor}
64+
65+
# Create Constructor and Execute Encode Method
66+
constructor = constructor_lookup[args["format"]]
67+
features = constructor(query_results, args["geom_col"]).encode()
68+
6369
# Setup and create request to Gist API
6470
gist_handler = GistAPIHandler(args["file"], args["description"], features)
6571
gist_handler.create()

pgsql2gist/geojson.py renamed to pgsql2gist/constructors.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
__author__ = 'matt'
22
__date__ = '11/24/13'
3+
"""
4+
Constructors are classes that are designed to accept geometry/attribute data as input,
5+
and convert to a serialized string, for POST'ing to Github using the Gist API.
6+
7+
Constructor classes rely on a duck typed interface. A stub class looks like the following:
8+
9+
class TopoJSONConstructor(object):
10+
def __init__(self, records, geom_col='geometry'):
11+
self.records = records
12+
self.geom_col = geom_col
13+
14+
def encode(self):
15+
raise NotImplementedError("TopoJSON Support Not Implemented In This Version.")
16+
17+
As seen above the required attributes for a constructor class are:
18+
records - A list of dictionaries. Each dictionary represents a record to be serialized.
19+
Dictionary key/values represent properties (tabular+geometry) for the record.
20+
This attribute can be populated from any data source, but within the context
21+
of this application, is the result of a call to psycopg2's fetchall() method.
22+
geom_col - A string representing the key for the a record dictionary (contained in the
23+
records list) that holds geometry information. Defaults to 'geometry'
24+
25+
An 'encode()' method is also required. This method should return a string representing the
26+
serialized geometry with attributes.
27+
"""
328

429
import collections
530
import json
@@ -17,8 +42,6 @@ class GeoJSONConstructor(object):
1742
records (LIST) - Each element is a dictionary representing
1843
columns and values for a single geojson feature.
1944
geom_col (STRING) - Indicates which dict key represents the geometry column.
20-
21-
TODO: Include validation checks. Add Exception Handling.
2245
"""
2346
def __init__(self, records, geom_col='geometry'):
2447
self.records = records
@@ -90,3 +113,21 @@ def encode(self):
90113
features = [self.make_feature(row, self.geom_col) for row in self.records]
91114
feature_collection = self.make_feature_collection(features)
92115
return feature_collection
116+
117+
118+
class TopoJSONConstructor(object):
119+
"""
120+
Given the following inputs, generate a TopoJSON feature collection.
121+
122+
Required Parameters:
123+
records (LIST) - Each element is a dictionary representing
124+
columns and values for a single geojson feature.
125+
geom_col (STRING) - Indicates which dict key represents the geometry column.
126+
"""
127+
128+
def __init__(self, records, geom_col='geometry'):
129+
self.records = records
130+
self.geom_col = geom_col
131+
132+
def encode(self):
133+
raise NotImplementedError("TopoJSON Support Not Implemented In This Version.")

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='pgsql2gist',
5-
version='0.2.1',
5+
version='0.2.2',
66
author='Matthew Kenny',
77
author_email='matthewkenny AT gmail DOT com',
88
classifiers=[

0 commit comments

Comments
 (0)