From 32cedc3a96cfe13f9dfb21a0a587289c90a39414 Mon Sep 17 00:00:00 2001 From: David Euresti Date: Fri, 8 Aug 2008 14:08:26 -0700 Subject: [PATCH] Split up finance.py and make it a python module, also added tests for it. --- finance.py | 309 ---------------------------------------------------- finance/__init__.py | 150 +++++++++++++++++++++++++ finance/service.py | 162 +++++++++++++++++++++++++++ finance_test.py | 48 ++++++++ 4 files changed, 360 insertions(+), 309 deletions(-) delete mode 100644 finance.py create mode 100644 finance/__init__.py create mode 100644 finance/service.py create mode 100644 finance_test.py diff --git a/finance.py b/finance.py deleted file mode 100644 index a9b2d20..0000000 --- a/finance.py +++ /dev/null @@ -1,309 +0,0 @@ -# -# Copyright (C) 2006 Google Inc. -# Copyright (C) 2008 David Euresti -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -try: - from xml.etree import cElementTree as ElementTree -except ImportError: - try: - import cElementTree as ElementTree - except ImportError: - from elementtree import ElementTree -import atom -import gdata - -GFIN_NAMESPACE = 'http://schemas.google.com/finance/2007' - -class PortfolioListEntry(gdata.GDataEntry): - """The Google Documents version of an Atom Entry""" - - _tag = 'entry' - _namespace = atom.ATOM_NAMESPACE - _children = gdata.GDataEntry._children.copy() - _attributes = gdata.GDataEntry._attributes.copy() - - -def PortfolioListEntryFromString(xml_string): - """Converts an XML string into a DocumentListEntry object. - - Args: - xml_string: string The XML describing a Document List feed entry. - - Returns: - A DocumentListEntry object corresponding to the given XML. - """ - return atom.CreateClassFromXMLString(PortfolioListEntry, xml_string) - - - -class PortfolioListFeed(gdata.GDataFeed): - """A feed containing a list of Google Documents Items""" - - _tag = 'feed' - _namespace = atom.ATOM_NAMESPACE - _children = gdata.GDataFeed._children.copy() - _attributes = gdata.GDataFeed._attributes.copy() - _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', - [PortfolioListEntry]) - - -def PortfolioListFeedFromString(xml_string): - """Converts an XML string into a DocumentListFeed object. - - Args: - xml_string: string The XML describing a DocumentList feed. - - Returns: - A DocumentListFeed object corresponding to the given XML. - """ - return atom.CreateClassFromXMLString(PortfolioListFeed, xml_string) - - -class Symbol(atom.AtomBase): - - _tag = 'symbol' - _namespace = GFIN_NAMESPACE - _children = atom.AtomBase._children.copy() - _attributes = atom.AtomBase._attributes.copy() - _attributes['symbol'] = 'symbol' - _attributes['fullName'] = 'fullName' - - def __init__(self, extension_elements=None, value=None, scope_type=None, - extension_attributes=None, text=None): - self.value = value - self.type = scope_type - self.text = text - self.extension_elements = extension_elements or [] - self.extension_attributes = extension_attributes or {} - -class PositionData(atom.AtomBase): - - _tag = 'positionData' - _namespace = GFIN_NAMESPACE - _children = atom.AtomBase._children.copy() - _attributes = atom.AtomBase._attributes.copy() - _attributes['shares'] = 'shares' - - def __init__(self, extension_elements=None, value=None, scope_type=None, - extension_attributes=None, text=None): - self.value = value - self.type = scope_type - self.text = text - self.extension_elements = extension_elements or [] - self.extension_attributes = extension_attributes or {} - - -class PositionListEntry(gdata.GDataEntry): - """The Google Documents version of an Atom Entry""" - - _tag = 'entry' - _namespace = atom.ATOM_NAMESPACE - _children = gdata.GDataEntry._children.copy() - _attributes = gdata.GDataEntry._attributes.copy() - - _children['{%s}symbol' % GFIN_NAMESPACE] = ('symbol', Symbol) - _children['{%s}positionData' % GFIN_NAMESPACE] = ('positionData', PositionData) - - -def PositionListEntryFromString(xml_string): - """Converts an XML string into a DocumentListEntry object. - - Args: - xml_string: string The XML describing a Document List feed entry. - - Returns: - A DocumentListEntry object corresponding to the given XML. - """ - return atom.CreateClassFromXMLString(PositionListEntry, xml_string) - - - -class PositionListFeed(gdata.GDataFeed): - """A feed containing a list of Google Documents Items""" - - _tag = 'feed' - _namespace = atom.ATOM_NAMESPACE - _children = gdata.GDataFeed._children.copy() - _attributes = gdata.GDataFeed._attributes.copy() - _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', - [PositionListEntry]) - - -def PositionListFeedFromString(xml_string): - """Converts an XML string into a DocumentListFeed object. - - Args: - xml_string: string The XML describing a DocumentList feed. - - Returns: - A DocumentListFeed object corresponding to the given XML. - """ - return atom.CreateClassFromXMLString(PositionListFeed, xml_string) - - -import urllib -import atom.service -import gdata.service -import gdata.docs - -class FinanceService(gdata.service.GDataService): - - def __init__(self, email=None, password=None, source=None, - server='finance.google.com', additional_headers=None): - """Constructor for the DocsService. - - Args: - email: string (optional) The e-mail address of the account to use for - authentication. - password: string (optional) The password of the account to use for - authentication. - source: string (optional) The name of the user's application. - server: string (optional) The server the feed is hosted on. - additional_headers: dict (optional) Any additional HTTP headers to be - transmitted to the service in the form of key-value - pairs. - - Yields: - A DocsService object used to communicate with the Google Documents - service. - """ - - gdata.service.GDataService.__init__(self, email=email, password=password, - service='finance', source=source, - server=server, - additional_headers=additional_headers) - - def Query(self, uri, converter=PortfolioListFeedFromString): - """Queries the Document List feed and returns the resulting feed of - entries. - - Args: - uri: string The full URI to be queried. This can contain query - parameters, a hostname, or simply the relative path to a Document - List feed. The DocumentQuery object is useful when constructing - query parameters. - converter: func (optional) A function which will be executed on the - retrieved item, generally to render it into a Python object. - By default the DocumentListFeedFromString function is used to - return a DocumentListFeed object. This is because most feed - queries will result in a feed and not a single entry. - """ - - return self.Get(uri, converter=converter) - - def QueryPortfolioListFeed(self, uri): - """Retrieves a DocumentListFeed by retrieving a URI based off the Document - List feed, including any query parameters. A DocumentQuery object can - be used to construct these parameters. - - Args: - uri: string The URI of the feed being retrieved possibly with query - parameters. - - Returns: - A DocumentListFeed object representing the feed returned by the server. - """ - return self.Get(uri, converter=PortfolioListFeedFromString) - - - def GetPortfolioListEntry(self, uri): - """Retrieves a particular DocumentListEntry by its unique URI. - - Args: - uri: string The unique URI of an entry in a Document List feed. - - Returns: - A DocumentListEntry object representing the retrieved entry. - """ - return self.Get(uri, converter=PortfolioListEntryFromString) - - def GetPortfolioListFeed(self): - """Retrieves a feed containing all of a user's documents.""" - - q = PortfolioQuery(); - return self.QueryPortfolioListFeed(q.ToUri()) - - - def QueryPositionListFeed(self, uri): - """Retrieves a DocumentListFeed by retrieving a URI based off the Document - List feed, including any query parameters. A DocumentQuery object can - be used to construct these parameters. - - Args: - uri: string The URI of the feed being retrieved possibly with query - parameters. - - Returns: - A DocumentListFeed object representing the feed returned by the server. - """ - return self.Get(uri, converter=PositionListFeedFromString) - - - def GetPositionListFeed(self, port): - uri = port.GetEditLink().href + '/positions' - print uri - return self.QueryPositionListFeed(uri) - -class PortfolioQuery(gdata.service.Query): - """Object used to construct a URI to query the Google Document List feed""" - - def __init__(self,feed='/finance/feeds/default', visibility='portfolios', - projection=None, text_query=None, params=None, - categories=None): - - """Constructor for Document List Query - - Args: - feed: string (optional) The path for the feed. (e.g. '/feeds/documents') - visibility: string (optional) The visibility chosen for the current feed. - projection: string (optional) The projection chosen for the current feed. - text_query: string (optional) The contents of the q query parameter. This - string is URL escaped upon conversion to a URI. - params: dict (optional) Parameter value string pairs which become URL - params when translated to a URI. These parameters are added to - the query's items. - categories: list (optional) List of category strings which should be - included as query categories. See gdata.service.Query for - additional documentation. - - Yields: - A DocumentQuery object used to construct a URI based on the Document - List feed. - """ - - self.visibility = visibility - self.projection = projection - gdata.service.Query.__init__(self, feed, text_query, params, categories) - - def ToUri(self): - """Generates a URI from the query parameters set in the object. - - Returns: - A string containing the URI used to retrieve entries from the Document - List feed. - """ - - old_feed = self.feed - if self.projection: - self.feed = '/'.join([old_feed, self.visibility, self.projection]) - else: - self.feed = '/'.join([old_feed, self.visibility]) - new_feed = gdata.service.Query.ToUri(self) - self.feed = old_feed - print 'feed = %s' % new_feed - return new_feed - - diff --git a/finance/__init__.py b/finance/__init__.py new file mode 100644 index 0000000..d15060a --- /dev/null +++ b/finance/__init__.py @@ -0,0 +1,150 @@ +# +# Copyright (C) 2006 Google Inc. +# Copyright (C) 2008 David Euresti +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +try: + from xml.etree import cElementTree as ElementTree +except ImportError: + try: + import cElementTree as ElementTree + except ImportError: + from elementtree import ElementTree + +import atom +import gdata + +GFIN_NAMESPACE = 'http://schemas.google.com/finance/2007' + +class PortfolioListEntry(gdata.GDataEntry): + _tag = 'entry' + _namespace = atom.ATOM_NAMESPACE + _children = gdata.GDataEntry._children.copy() + _attributes = gdata.GDataEntry._attributes.copy() + + +def PortfolioListEntryFromString(xml_string): + """Converts an XML string into a PortfolioListEntry object. + + Args: + xml_string: string The XML describing a Document List feed entry. + + Returns: + A DocumentListEntry object corresponding to the given XML. + """ + return atom.CreateClassFromXMLString(PortfolioListEntry, + xml_string) + +class PortfolioListFeed(gdata.GDataFeed): + """A feed containing a list of Portfolio Items""" + + _tag = 'feed' + _namespace = atom.ATOM_NAMESPACE + _children = gdata.GDataFeed._children.copy() + _attributes = gdata.GDataFeed._attributes.copy() + _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', + [PortfolioListEntry]) + +def PortfolioListFeedFromString(xml_string): + """Converts an XML string into a PortfolioListFeed object. + + Args: + xml_string: string The XML describing a PortfolioList feed. + + Returns: + A PortfolioListFeed object corresponding to the given XML. + """ + return atom.CreateClassFromXMLString(PortfolioListFeed, xml_string) + + +class Symbol(atom.AtomBase): + + _tag = 'symbol' + _namespace = GFIN_NAMESPACE + _children = atom.AtomBase._children.copy() + _attributes = atom.AtomBase._attributes.copy() + _attributes['symbol'] = 'symbol' + _attributes['fullName'] = 'fullName' + + def __init__(self, extension_elements=None, value=None, scope_type=None, + extension_attributes=None, text=None): + self.value = value + self.type = scope_type + self.text = text + self.extension_elements = extension_elements or [] + self.extension_attributes = extension_attributes or {} + +class PositionData(atom.AtomBase): + + _tag = 'positionData' + _namespace = GFIN_NAMESPACE + _children = atom.AtomBase._children.copy() + _attributes = atom.AtomBase._attributes.copy() + _attributes['shares'] = 'shares' + + def __init__(self, extension_elements=None, value=None, scope_type=None, + extension_attributes=None, text=None): + self.value = value + self.type = scope_type + self.text = text + self.extension_elements = extension_elements or [] + self.extension_attributes = extension_attributes or {} + + +class PositionListEntry(gdata.GDataEntry): + _tag = 'entry' + _namespace = atom.ATOM_NAMESPACE + _children = gdata.GDataEntry._children.copy() + _attributes = gdata.GDataEntry._attributes.copy() + + _children['{%s}symbol' % GFIN_NAMESPACE] = ('symbol', Symbol) + _children['{%s}positionData' % GFIN_NAMESPACE] = ('positionData', + PositionData) + + +def PositionListEntryFromString(xml_string): + """Converts an XML string into a PositionListEntry object. + + Args: + xml_string: string The XML describing a Position List feed entry. + + Returns: + A PositionListEntry object corresponding to the given XML. + """ + return atom.CreateClassFromXMLString(PositionListEntry, xml_string) + + + +class PositionListFeed(gdata.GDataFeed): + """A feed containing a list of Position Items""" + + _tag = 'feed' + _namespace = atom.ATOM_NAMESPACE + _children = gdata.GDataFeed._children.copy() + _attributes = gdata.GDataFeed._attributes.copy() + _children['{%s}entry' % atom.ATOM_NAMESPACE] = ('entry', + [PositionListEntry]) + + +def PositionListFeedFromString(xml_string): + """Converts an XML string into a PositionListFeed object. + + Args: + xml_string: string The XML describing a PositionList feed. + + Returns: + A PositionListFeed object corresponding to the given XML. + """ + return atom.CreateClassFromXMLString(PositionListFeed, xml_string) diff --git a/finance/service.py b/finance/service.py new file mode 100644 index 0000000..de56a80 --- /dev/null +++ b/finance/service.py @@ -0,0 +1,162 @@ +# +# Copyright (C) 2006 Google Inc. +# Copyright (C) 2008 David Euresti +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import urllib +import atom.service +import gdata.service +import finance + +class FinanceService(gdata.service.GDataService): + + def __init__(self, email=None, password=None, source=None, + server='finance.google.com', additional_headers=None): + """Constructor for the FinanceService. + + Args: + email: string (optional) The e-mail address of the account to use for + authentication. + password: string (optional) The password of the account to use for + authentication. + source: string (optional) The name of the user's application. + server: string (optional) The server the feed is hosted on. + additional_headers: dict (optional) Any additional HTTP headers to be + transmitted to the service in the form of + key-value pairs. + + Yields: + A FinanceService object used to communicate with the Google Finance + service. + """ + + gdata.service.GDataService.__init__( + self, email=email, password=password, service='finance', + source=source, server=server, + additional_headers=additional_headers) + + def QueryPortfolioListFeed(self, uri): + """Retrieves a PortfolioListFeed by retrieving a URI based off the + Portfolio List feed, including any query parameters. A PortfolioQuery + object can be used to construct these parameters. + + Args: + uri: string The URI of the feed being retrieved possibly with query + parameters. + + Returns: + A PortfolioListFeed object representing the feed returned by the + server. + """ + return self.Get(uri, converter=finance.PortfolioListFeedFromString) + + + def GetPortfolioListEntry(self, uri): + """Retrieves a particular DocumentListEntry by its unique URI. + + Args: + uri: string The unique URI of an entry in a Document List feed. + + Returns: + A DocumentListEntry object representing the retrieved entry. + """ + return self.Get(uri, converter=finance.PortfolioListEntryFromString) + + + def GetPortfolioListFeed(self): + """Retrieves a feed containing all of a user's documents.""" + + q = PortfolioQuery(); + return self.QueryPortfolioListFeed(q.ToUri()) + + def QueryPositionListFeed(self, uri): + """Retrieves a DocumentListFeed by retrieving a URI based off the + Document List feed, including any query parameters. A DocumentQuery + object can be used to construct these parameters. + + Args: + uri: string The URI of the feed being retrieved possibly with query + parameters. + + Returns: + A DocumentListFeed object representing the feed returned by the server. + """ + return self.Get(uri, converter=finance.PositionListFeedFromString) + + + def GetPositionListFeed(self, port): + uri = port.GetEditLink().href + '/positions' + print uri + return self.QueryPositionListFeed(uri) + +class PortfolioQuery(gdata.service.Query): + """Object used to construct a URI to query the Google Portfolio List feed + """ + + def __init__(self,feed='/finance/feeds/default', visibility='portfolios', + projection=None, text_query=None, params=None, + categories=None): + + """Constructor for Portfolio List Query + + Args: + + feed: string (optional) The path for the feed. + + visibility: string (optional) The visibility chosen for the current + feed. + projection: string (optional) The projection chosen for the current + feed. + + text_query: string (optional) The contents of the q query + parameter. This string is URL escaped upon conversion to + a URI. + + params: dict (optional) Parameter value string pairs which become URL + params when translated to a URI. These parameters are added + to the query's items. + + categories: list (optional) List of category strings which should be + included as query categories. See gdata.service.Query for + additional documentation. + + Yields: + A DocumentQuery object used to construct a URI based on the Document + List feed. + """ + + self.visibility = visibility + self.projection = projection + gdata.service.Query.__init__(self, feed, text_query, params, + categories) + + def ToUri(self): + """Generates a URI from the query parameters set in the object. + + Returns: + A string containing the URI used to retrieve entries from the + Document List feed. + """ + + old_feed = self.feed + if self.projection: + self.feed = '/'.join([old_feed, self.visibility, self.projection]) + else: + self.feed = '/'.join([old_feed, self.visibility]) + new_feed = gdata.service.Query.ToUri(self) + self.feed = old_feed + print 'feed = %s' % new_feed + return new_feed + + diff --git a/finance_test.py b/finance_test.py new file mode 100644 index 0000000..1f6bdf7 --- /dev/null +++ b/finance_test.py @@ -0,0 +1,48 @@ +import unittest +import finance +import finance.service +import os +import getpass + +def make_client(): + if not os.environ.has_key('GOOGLE_USER'): + raise Exception('"GOOGLE_USER not set') + else: + user = os.environ['GOOGLE_USER'] + if not os.environ.has_key('GOOGLE_PASSWORD'): + password = getpass.getpass('Enter password for %s: ' % + user) + else: + password = os.environ['GOOGLE_PASSWORD'] + + client = finance.service.FinanceService() + client.ClientLogin(user, password) + return client + + +class TestSequenceFunctions(unittest.TestCase): + user = None + password = None + + def setUp(self): + if not self.user: + if not os.environ.has_key('GOOGLE_USER'): + raise Exception('"GOOGLE_USER not set') + else: + self.user = os.environ['GOOGLE_USER'] + if not self.password: + if not os.environ.has_key('GOOGLE_PASSWORD'): + self.password = getpass.getpass('Enter password for %s: ' % + self.user) + else: + self.password = os.environ['GOOGLE_PASSWORD'] + + self.client = finance.service.FinanceService() + self.client.ClientLogin(self.user, self.password) + + def testGetPortfolioFeed(self): + feed = self.client.GetPortfolioListFeed() + print feed + +if __name__ == '__main__': + unittest.main() -- 2.11.4.GIT