Skip to content

Commit

Permalink
Merge branch 'v0.4.x' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
funbaker committed Oct 20, 2016
2 parents 576ffcf + ad3c5f9 commit 9705ab4
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 92 deletions.
22 changes: 22 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
0.4 (unreleased)
----------------
* Use astropy tables for table metadata

* fix another content encoding error

0.3.2 (unreleased)
------------------
* Adding table property to DALResults. This is a shortcut to access the astropy table

* Improved Error Handling

0.3.1 (unreleased)
------------------
* fix an error where the content wasn't decoded properly

* fix a bug where POST parameters are submitted as GET parameters

0.3 (unreleased)
----------------
Adding TAP API

0.1 (unreleased)
----------------

Expand Down
8 changes: 5 additions & 3 deletions docs/pyvo/data_access.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1250,10 +1250,12 @@ datetime.datetime(2000, 0, 0, 0, 0, 0)
>>> print(service.tables.keys())

The keys within tables are the fully qualified table names as they can
be used in queries. To inspect the column metadata for a table, see its
name's value in the tables dictionary.
be used in queries. To inspect the column metadata for a table, see the column
property of a give table.

>>> print(str(service.tables["rave.main"]))
>>> service.tables["rave.main"].columns

See also http://docs.astropy.org/en/stable/table/index.html.

.. note::
Some TAP services have tables metadata of several megabytes.
Expand Down
19 changes: 18 additions & 1 deletion pyvo/dal/tap.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ def availability(self):
if self._availability == (None, None):
r = requests.get(
'{0}/availability'.format(self.baseurl), stream = True)

# requests doesn't decode the content by default
r.raw.read = functools.partial(r.raw.read, decode_content=True)

self._availability = vosi.parse_availability(r.raw)
return self._availability

Expand Down Expand Up @@ -136,6 +140,10 @@ def capabilities(self):
if self._capabilities is None:
r = requests.get(
'{0}/capabilities'.format(self.baseurl), stream = True)

# requests doesn't decode the content by default
r.raw.read = functools.partial(r.raw.read, decode_content=True)

self._capabilities = vosi.parse_capabilities(r.raw)
return self._capabilities

Expand All @@ -146,6 +154,10 @@ def tables(self):
"""
if self._tables is None:
r = requests.get('{0}/tables'.format(self.baseurl), stream = True)

# requests doesn't decode the content by default
r.raw.read = functools.partial(r.raw.read, decode_content=True)

self._tables = vosi.parse_tables(r.raw)
return self._tables

Expand Down Expand Up @@ -403,6 +415,7 @@ def submit(self):

r = requests.post(url, data = self._param, stream = True,
files = files)
# requests doesn't decode the content by default
r.raw.read = functools.partial(r.raw.read, decode_content=True)
return r

Expand Down Expand Up @@ -457,8 +470,11 @@ def _update(self):
r.raise_for_status()
except requests.exceptions.RequestException as ex:
raise DALServiceError.from_except(ex, self.url, "TAP", "1.0")

# requests doesn't decode the content by default
r.raw.read = functools.partial(r.raw.read, decode_content=True)

self._job.update(uws.parse_job(r.raw))
pass

@property
def job(self):
Expand Down Expand Up @@ -572,6 +588,7 @@ def result_uris(self):
"""
a list of the last result uri's
"""
self.raise_if_error()
return self._job["results"]

@property
Expand Down
130 changes: 43 additions & 87 deletions pyvo/tools/vosi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from . import plainxml
import datetime
from collections import OrderedDict
import StringIO
from astropy.table import Table, Column
from astropy.io.votable.converters import get_converter
import numpy as np

class _CapabilitiesParser(plainxml.StartEndHandler):
# VOSI; each capability is a dict with at least a key interfaces.
Expand Down Expand Up @@ -196,7 +198,7 @@ def parse_capabilities(stream):
class _TablesParser(plainxml.StartEndHandler):
def __init__(self):
plainxml.StartEndHandler.__init__(self)
self.tables = _TableDict()
self.tables = OrderedDict()

def _start_schema(self, name, attrs):
self.curSchema = ""
Expand All @@ -205,128 +207,82 @@ def _end_schema(self, name, attrs, content):
self.curSchema = None

def _start_table(self, name, attrs):
self.curTable = _Table()
self.curTable = Table()

def _end_table(self, name, attrs, content):
# table names should be exposed the same way they are accessed in ADQL
fqtn = ".".join((self.curSchema, self.curTable.name))
self.curTable._fqdn = fqtn
self.curTable._schema = self.curSchema
self.tables[fqtn] = self.curTable
table_name = self.curTable.meta["name"]
self.tables[table_name] = self.curTable
self.curTable = None

def _start_column(self, name, attrs):
self.curColumn = _Column()
self.inColumn = True

def _end_column(self, name, attrs, content):
self.curTable[self.curColumn.name] = self.curColumn
self.curColumn = None
column = Column(
name = self.curColumn, dtype = self.curDtype,
description = self.curDescription,
unit = getattr(self, "curUnit", None))
column.meta["ucd"] = self.curUcd
column.meta["datatype"] = self.curDatatype
column.meta["arraysize"] = self.curArraysize
self.curTable[self.curColumn] = column
self.inColumn = False

def _end_name(self, name, attrs, content):
content = content.strip()

if getattr(self, "curColumn", None) is not None:
self.curColumn._name = content
if getattr(self, "inColumn", False):
self.curColumn = content
elif getattr(self, "curTable", None) is not None:
# return the last tuple from dot notation
self.curTable._name = content.split(".")[-1]
elif getattr(self, "curSchema", None) is not None:
self.curSchema = content
self.curTable.meta["name"] = content

def _end_description(self, name, attrs, content):
content = content.strip()

if getattr(self, "curColumn", None) is not None:
self.curColumn._description = content
if getattr(self, "inColumn", False):
self.curDescription = content

def _end_ucd(self, name, attrs, content):
content = content.strip()

if getattr(self, "curColumn", None) is not None:
self.curColumn._ucd = content
if getattr(self, "inColumn", False):
self.curUcd = content

def _end_dataType(self, name, attrs, content):
content = content.strip()

if getattr(self, "curColumn", None) is not None:
self.curColumn._data_type = content
class _values(object):
null = None

class _field(object):
datatype = content
arraysize = attrs.get("arraysize") if content in (
"char", "unicodeChar") else None
precision = None
width = None
values = _values()


converter = get_converter(_field())
self.curDtype = np.dtype(converter.format)
self.curDatatype = content
self.curArraysize = attrs.get("arraysize")

def _end_unit(self, name, attrs, content):
content = content.strip()

if getattr(self, "curColumn", None) is not None:
self.curColumn._unit = content
if getattr(self, "inColumn", False):
self.curUnit = content

def getResult(self):
return self.tables


def parse_tables(stream):
parser = _TablesParser()
parser.parse(stream)
return parser.getResult()

class _TableDict(OrderedDict):
def __str__(self):
return "\n".join(unicode(t) for t in self.values())

class _Table(OrderedDict):
def __init__(self):
super(_Table, self).__init__()
self._schema = None
self._name = None

def __str__(self):
io = StringIO.StringIO()
io.write("{0}.{1}\n".format(self.schema, self.name))

for k, v in self.items():
s = "\n".join(
map(lambda x: "\t{0}".format(x),
unicode(v).split("\n")[:-1]))
io.write(unicode("{0}\n".format(s)))

return io.getvalue()

@property
def name(self):
return self._name

@property
def schema(self):
return self._schema

class _Column(object):
def __init__(self):
self._name = ""
self._ucd = ""
self._data_type = ""
self._unit = ""
self._description = ""

def __str__(self):
ret = "{0} {1} {2} {3}\n\t{4}\n".format(
self.name, self.ucd, self.data_type, self.unit, self.description)
return ret

@property
def name(self):
return self._name

@property
def ucd(self):
return self._ucd

@property
def data_type(self):
return self._data_type

@property
def unit(self):
return self._unit

@property
def description(self):
return self._description

class _AvailabiliyParser(plainxml.StartEndHandler):
def __init__(self):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
builtins._ASTROPY_PACKAGE_NAME_ = PACKAGENAME

# VERSION should be PEP386 compatible (http://www.python.org/dev/peps/pep-0386)
VERSION = '0.3.2'
VERSION = '0.4'

# Indicates if this version is a release version
RELEASE = 'dev' not in VERSION
Expand Down

0 comments on commit 9705ab4

Please sign in to comment.