ofxtools 0.5.1__tar.gz → 0.5.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {ofxtools-0.5.1/ofxtools.egg-info → ofxtools-0.5.2}/PKG-INFO +145 -24
  2. {ofxtools-0.5.1 → ofxtools-0.5.2}/README.rst +143 -21
  3. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/Client.py +103 -17
  4. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/Parser.py +2 -6
  5. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/Types.py +35 -25
  6. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/header.py +48 -23
  7. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/creditcard.py +78 -7
  8. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/ofx.py +3 -1
  9. ofxtools-0.5.2/ofxtools/models/signup.py +120 -0
  10. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/utils.py +27 -0
  11. {ofxtools-0.5.1 → ofxtools-0.5.2/ofxtools.egg-info}/PKG-INFO +145 -24
  12. {ofxtools-0.5.1 → ofxtools-0.5.2}/setup.py +2 -2
  13. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_bank.py +9 -7
  14. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_creditcard.py +133 -2
  15. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_header.py +43 -4
  16. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_investment.py +9 -8
  17. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_models_common.py +2 -1
  18. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_models_ofx.py +7 -4
  19. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_parser.py +38 -36
  20. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_profile.py +3 -2
  21. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_seclist.py +7 -6
  22. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_signon.py +6 -5
  23. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_types.py +40 -20
  24. ofxtools-0.5.1/ofxtools/models/signup.py +0 -44
  25. {ofxtools-0.5.1 → ofxtools-0.5.2}/LICENSE +0 -0
  26. {ofxtools-0.5.1 → ofxtools-0.5.2}/MANIFEST.in +0 -0
  27. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/__init__.py +0 -0
  28. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/config/fi.cfg +0 -0
  29. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/config/ofxget_example.cfg +0 -0
  30. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/legacyclient.py +0 -0
  31. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/lib.py +0 -0
  32. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/__init__.py +0 -0
  33. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/bank.py +0 -0
  34. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/base.py +0 -0
  35. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/common.py +0 -0
  36. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/i18n.py +0 -0
  37. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/investment.py +0 -0
  38. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/profile.py +0 -0
  39. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/seclist.py +0 -0
  40. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/signon.py +0 -0
  41. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/models/tax1099.py +0 -0
  42. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/ofxalchemy/Parser.py +0 -0
  43. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/ofxalchemy/Types.py +0 -0
  44. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/ofxalchemy/__init__.py +0 -0
  45. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/ofxalchemy/database.py +0 -0
  46. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools/ofxalchemy/models.py +0 -0
  47. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools.egg-info/SOURCES.txt +0 -0
  48. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools.egg-info/dependency_links.txt +0 -0
  49. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools.egg-info/entry_points.txt +0 -0
  50. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools.egg-info/requires.txt +0 -0
  51. {ofxtools-0.5.1 → ofxtools-0.5.2}/ofxtools.egg-info/top_level.txt +0 -0
  52. {ofxtools-0.5.1 → ofxtools-0.5.2}/setup.cfg +0 -0
  53. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/__init__.py +0 -0
  54. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/base.py +0 -0
  55. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_alchemy.py +0 -0
  56. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_client.py +0 -0
  57. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_i18n.py +0 -0
  58. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_parser_functional.py +0 -0
  59. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_signup.py +0 -0
  60. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_tax1099.py +0 -0
  61. {ofxtools-0.5.1 → ofxtools-0.5.2}/tests/test_utils.py +0 -0
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: ofxtools
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Library for working with Open Financial Exchange (OFX) formatted data used by financial institutions
5
5
  Home-page: https://github.com/csingley/ofxtools
6
6
  Author: Christopher Singley
7
7
  Author-email: csingley@gmail.com
8
8
  License: MIT
9
- Download-URL: https://github.com/csingley/ofxtools/tarball/0.5.1
10
- Description-Content-Type: UNKNOWN
9
+ Download-URL: https://github.com/csingley/ofxtools/tarball/0.5.2
11
10
  Description: ====================
12
11
  OFX tools for Python
13
12
  ====================
@@ -27,7 +26,7 @@ Description: ====================
27
26
  ElementTree structure, then converts the parsed data into normal Python
28
27
  types (e.g. datetime.datetime, list) and exposes them through more Pythonic
29
28
  attribute access (e.g. ``OFX.statements[0].ledgerbal``); and
30
- - An (optional) ``ofxalchemy`` object model that persists OFX data in an
29
+ - A (deprecated) ``ofxalchemy`` object model that persists OFX data in an
31
30
  SQL database where they can be queried.
32
31
 
33
32
  Installation
@@ -39,18 +38,20 @@ Description: ====================
39
38
  pip install ofxtools
40
39
 
41
40
  To install the most recent prerelease (which is where the magic happens, and
42
- also the bugs), you can download the `current master`_ and unzip it. Since
43
- dependencies are minimal, it's recommended to use the Python user installation
44
- scheme:
41
+ also the bugs), you can download the `current master`_, unzip it, and install
42
+ via the included setup file:
45
43
 
46
44
  ::
47
45
 
48
- python setup.py install --user
46
+ python setup.py install
49
47
 
50
48
  In addition to the Python package, this will also install a script ``ofxget``
51
49
  in ``~/.local/bin``, and its sample configuration file in
52
50
  ``~/.config/ofxtools``.
53
51
 
52
+ For any installation method, it's recommended to install ``ofxtools`` in a
53
+ `virtual environment`_.
54
+
54
55
  OFX Client
55
56
  ==========
56
57
 
@@ -181,6 +182,129 @@ Description: ====================
181
182
  In [23]: ET.tostring(tree)[:512] # Back to str
182
183
  Out[23]: b'<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY><MESSAGE>Success</MESSAGE></STATUS><DTSERVER>20170421170513</DTSERVER><LANGUAGE>ENG</LANGUAGE><FI><ORG>Ameritrade Technology Group</ORG><FID>AIS</FID></FI></SONRS></SIGNONMSGSRSV1><INVSTMTMSGSRSV1><INVSTMTTRNRS><TRNUID>2a656f1c-5f86-4265-84f1-6c7f0dc8c370</TRNUID><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY><MESSAGE>pr-ctlvofx-pp03-clientsys Success</MESSAGE></STATUS><INVSTMTRS><DTASOF>20170401030609</DTASOF><CURDEF>USD</CURDEF><IN'
183
184
 
185
+ ofxtools and SQL
186
+ ================
187
+
188
+ ``ofxtools`` does include the ``ofxalchemy`` subpackage, but you probably don't
189
+ want to use it. The implementation is pretty nasty, and the SQL tables it
190
+ generates are cumbersome and inefficient.
191
+
192
+ Frankly, OFX is a poor data format for serious use, as is obvious to anyone
193
+ who's tried to work with its handling of online bill payees or securities
194
+ reorganizations. A better approach is to decouple your SQL data model from
195
+ OFX, which will also allow you to better handle other financial data formats.
196
+
197
+ It's recommended to define your own ORM models based on your needs. Import
198
+ OFX into Python using the main ``ofxtools.Parser.OFXTree`` parser, extract
199
+ the relevant data, and feed it to your model classes. Something like this:
200
+
201
+ .. code:: python
202
+
203
+ from sqlalchemy.ext.declarative import declarative_base
204
+ from sqlalchemy import (
205
+ Column, Integer, String, Text, DateTime, Numeric, ForeignKey, Enum,
206
+ )
207
+ from sqlalchemy.orm import (relationship, sessionmaker, )
208
+ from sqlalchemy import create_engine
209
+
210
+ from ofxtools.models.i18n import CURRENCY_CODES
211
+ from ofxtools.Client import (OFXClient, InvStmtRq, )
212
+ from ofxtools.Parser import OFXTree
213
+ from ofxtools.models.investment import (BUYSTOCK, SELLSTOCK)
214
+
215
+
216
+ # Data model
217
+ Base = declarative_base()
218
+
219
+
220
+ class Account(Base):
221
+ id = Column(Integer, primary_key=True)
222
+ brokerid = Column(String, nullable=False, unique=True)
223
+ number = Column(String, nullable=False)
224
+ name = Column(String)
225
+
226
+
227
+ class Security(Base):
228
+ id = Column(Integer, primary_key=True)
229
+ name = Column(String)
230
+ ticker = Column(String)
231
+ uniqueidtype = Column(String, nullable=False)
232
+ uniqueid = Column(String, nullable=False)
233
+
234
+
235
+ class Transaction(Base):
236
+ id = Column(Integer, primary_key=True)
237
+ uniqueid = Column(String, nullable=False, unique=True)
238
+ datetime = Column(DateTime, nullable=False)
239
+ dtsettle = Column(DateTime)
240
+ type = Column(Enum('returnofcapital', 'split', 'spinoff', 'transfer',
241
+ 'trade', 'exercise', name='transaction_type'),
242
+ nullable=False)
243
+ memo = Column(Text)
244
+ currency = Column(Enum(*CURRENCY_CODES, name='transaction_currency'))
245
+ cash = Column(Numeric)
246
+ account_id = Column(Integer,
247
+ ForeignKey('account.id', onupdate='CASCADE'),
248
+ nullable=False)
249
+ account = relationship('Account', foreign_keys=[account_id],
250
+ backref='transactions')
251
+ security_id = Column(Integer,
252
+ ForeignKey('security.id', onupdate='CASCADE'),
253
+ nullable=False)
254
+ security = relationship('Security', foreign_keys=[security_id],
255
+ backref='transactions')
256
+ units = Column(Numeric)
257
+
258
+
259
+ # Import
260
+ client = OFXClient('https://ofxs.ameritrade.com/cgi-bin/apps/OFX',
261
+ org='Ameritrade Technology Group', fid='AIS',
262
+ brokerid='ameritrade.com')
263
+ stmtrq = InvStmtRq(acctid='999999999')
264
+ response = client.request_statements(user='elmerfudd',
265
+ password='T0PS3CR3T', invstmtrqs=[stmtrq])
266
+ parser = OFXTree()
267
+ parser.parse(response)
268
+ ofx = parser.convert()
269
+
270
+
271
+ # Extract
272
+ def make_security(secinfo):
273
+ return Security(
274
+ name=secinfo.secname, ticker=secinfo.ticker,
275
+ uniqueidtype=secinfo.uniqueidtype, uniqueid=secinfo.uniqueid)
276
+
277
+
278
+ securities = {(sec.uniqueidtype, sec.uniqueid): make_security(sec)
279
+ for sec in ofx.securities}
280
+
281
+
282
+ stmt = ofx.statements[0]
283
+ account = Account(brokerid=stmt.brokerid, number=stmt.acctid)
284
+
285
+
286
+ def make_trade(invtran):
287
+ security = securities[(invtran.uniqueidtype, invtran.uniqueid)]
288
+ return Transaction(
289
+ uniqueid=invtran.fitid, datetime=invtran.dttrade,
290
+ dtsettle=invtran.dtsettle, type='trade', memo=invtran.memo,
291
+ currency=invtran.currency, cash=invtran.total, account=account,
292
+ security=security, units=invtran.units)
293
+
294
+
295
+ trades = [make_trade(tx) for tx in stmt.transactions
296
+ if isinstance(tx, (BUYSTOCK, SELLSTOCK))] # dispatch by model class
297
+
298
+
299
+ # Persist
300
+ engine = create_engine('')
301
+ Session = sessionmaker(bind=engine)
302
+ session = Session()
303
+ session.add(account)
304
+ session.add_all(securities.values())
305
+ session.add_all(trades)
306
+ session.commit()
307
+
184
308
  Contributing
185
309
  ============
186
310
 
@@ -191,16 +315,20 @@ Description: ====================
191
315
 
192
316
  git clone https://github.com/csingley/ofxtools.git
193
317
 
194
- Feel free to `create pull requests`_ on `ofxtools repository on GitHub`_.
318
+ Set up a `virtual environment`_, and install the package in development mode
319
+ so you're working on live code:
195
320
 
196
- Again, the minimal dependencies make it simple to install with the Python user
197
- installation scheme:
321
+ ::
322
+
323
+ python setup.py develop
324
+
325
+ Install all development requirements:
198
326
 
199
327
  ::
200
328
 
201
- python setup.py develop --user
329
+ pip install -r requirements-development.txt
202
330
 
203
- However, you'll want to run the tests, either with ``make``:
331
+ Run the tests, either with ``make``:
204
332
 
205
333
  ::
206
334
 
@@ -210,18 +338,10 @@ Description: ====================
210
338
 
211
339
  ::
212
340
 
213
- nosetests -dsv --with-yanc --with-coverage --cover-package ofxtools
214
-
215
-
216
- if you don't already have `nose`, `coverage`, etc. installed, and you don't
217
- want to clutter your system libraries just for this work, you can create a
218
- `virtual environment`_ and install all development requirements:
341
+ nosetests -dsv --with-coverage --cover-package ofxtools
219
342
 
220
- ::
343
+ Feel free to `create pull requests`_ on `ofxtools repository on GitHub`_.
221
344
 
222
- virtualenv .venv
223
- source .venv/bin/activate
224
- pip install -r requirements-development.txt
225
345
 
226
346
  Resources
227
347
  =========
@@ -236,14 +356,15 @@ Description: ====================
236
356
  .. _Requests: http://docs.python-requests.org/en/master/
237
357
  .. _PyPI: https://pypi.python.org/pypi/ofxtools
238
358
  .. _current master: https://github.com/csingley/ofxtools/archive/master.zip
359
+ .. _virtual environment: https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments
239
360
  .. _OFX spec: http://www.ofx.net/downloads.html
240
361
  .. _Git: https://git-scm.com/
241
362
  .. _create pull requests: https://help.github.com/articles/using-pull-requests/
242
363
  .. _ofxtools repository on GitHub: https://github.com/csingley/ofxtools
243
- .. _virtual environment: http://docs.python-guide.org/en/latest/dev/virtualenvs/
244
364
  .. _Quicken data mapping guide: https://fi.intuit.com/downloads/QW_DataMappingGuide.pdf
245
365
  .. _OFX Home: http://www.ofxhome.com/
246
366
 
367
+
247
368
  Keywords: ofx,Open Financial Exchange
248
369
  Platform: UNKNOWN
249
370
  Classifier: Development Status :: 3 - Alpha
@@ -17,7 +17,7 @@ The primary facilities provided include:
17
17
  ElementTree structure, then converts the parsed data into normal Python
18
18
  types (e.g. datetime.datetime, list) and exposes them through more Pythonic
19
19
  attribute access (e.g. ``OFX.statements[0].ledgerbal``); and
20
- - An (optional) ``ofxalchemy`` object model that persists OFX data in an
20
+ - A (deprecated) ``ofxalchemy`` object model that persists OFX data in an
21
21
  SQL database where they can be queried.
22
22
 
23
23
  Installation
@@ -29,18 +29,20 @@ Installation
29
29
  pip install ofxtools
30
30
 
31
31
  To install the most recent prerelease (which is where the magic happens, and
32
- also the bugs), you can download the `current master`_ and unzip it. Since
33
- dependencies are minimal, it's recommended to use the Python user installation
34
- scheme:
32
+ also the bugs), you can download the `current master`_, unzip it, and install
33
+ via the included setup file:
35
34
 
36
35
  ::
37
36
 
38
- python setup.py install --user
37
+ python setup.py install
39
38
 
40
39
  In addition to the Python package, this will also install a script ``ofxget``
41
40
  in ``~/.local/bin``, and its sample configuration file in
42
41
  ``~/.config/ofxtools``.
43
42
 
43
+ For any installation method, it's recommended to install ``ofxtools`` in a
44
+ `virtual environment`_.
45
+
44
46
  OFX Client
45
47
  ==========
46
48
 
@@ -171,6 +173,129 @@ Usage Example
171
173
  In [23]: ET.tostring(tree)[:512] # Back to str
172
174
  Out[23]: b'<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY><MESSAGE>Success</MESSAGE></STATUS><DTSERVER>20170421170513</DTSERVER><LANGUAGE>ENG</LANGUAGE><FI><ORG>Ameritrade Technology Group</ORG><FID>AIS</FID></FI></SONRS></SIGNONMSGSRSV1><INVSTMTMSGSRSV1><INVSTMTTRNRS><TRNUID>2a656f1c-5f86-4265-84f1-6c7f0dc8c370</TRNUID><STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY><MESSAGE>pr-ctlvofx-pp03-clientsys Success</MESSAGE></STATUS><INVSTMTRS><DTASOF>20170401030609</DTASOF><CURDEF>USD</CURDEF><IN'
173
175
 
176
+ ofxtools and SQL
177
+ ================
178
+
179
+ ``ofxtools`` does include the ``ofxalchemy`` subpackage, but you probably don't
180
+ want to use it. The implementation is pretty nasty, and the SQL tables it
181
+ generates are cumbersome and inefficient.
182
+
183
+ Frankly, OFX is a poor data format for serious use, as is obvious to anyone
184
+ who's tried to work with its handling of online bill payees or securities
185
+ reorganizations. A better approach is to decouple your SQL data model from
186
+ OFX, which will also allow you to better handle other financial data formats.
187
+
188
+ It's recommended to define your own ORM models based on your needs. Import
189
+ OFX into Python using the main ``ofxtools.Parser.OFXTree`` parser, extract
190
+ the relevant data, and feed it to your model classes. Something like this:
191
+
192
+ .. code:: python
193
+
194
+ from sqlalchemy.ext.declarative import declarative_base
195
+ from sqlalchemy import (
196
+ Column, Integer, String, Text, DateTime, Numeric, ForeignKey, Enum,
197
+ )
198
+ from sqlalchemy.orm import (relationship, sessionmaker, )
199
+ from sqlalchemy import create_engine
200
+
201
+ from ofxtools.models.i18n import CURRENCY_CODES
202
+ from ofxtools.Client import (OFXClient, InvStmtRq, )
203
+ from ofxtools.Parser import OFXTree
204
+ from ofxtools.models.investment import (BUYSTOCK, SELLSTOCK)
205
+
206
+
207
+ # Data model
208
+ Base = declarative_base()
209
+
210
+
211
+ class Account(Base):
212
+ id = Column(Integer, primary_key=True)
213
+ brokerid = Column(String, nullable=False, unique=True)
214
+ number = Column(String, nullable=False)
215
+ name = Column(String)
216
+
217
+
218
+ class Security(Base):
219
+ id = Column(Integer, primary_key=True)
220
+ name = Column(String)
221
+ ticker = Column(String)
222
+ uniqueidtype = Column(String, nullable=False)
223
+ uniqueid = Column(String, nullable=False)
224
+
225
+
226
+ class Transaction(Base):
227
+ id = Column(Integer, primary_key=True)
228
+ uniqueid = Column(String, nullable=False, unique=True)
229
+ datetime = Column(DateTime, nullable=False)
230
+ dtsettle = Column(DateTime)
231
+ type = Column(Enum('returnofcapital', 'split', 'spinoff', 'transfer',
232
+ 'trade', 'exercise', name='transaction_type'),
233
+ nullable=False)
234
+ memo = Column(Text)
235
+ currency = Column(Enum(*CURRENCY_CODES, name='transaction_currency'))
236
+ cash = Column(Numeric)
237
+ account_id = Column(Integer,
238
+ ForeignKey('account.id', onupdate='CASCADE'),
239
+ nullable=False)
240
+ account = relationship('Account', foreign_keys=[account_id],
241
+ backref='transactions')
242
+ security_id = Column(Integer,
243
+ ForeignKey('security.id', onupdate='CASCADE'),
244
+ nullable=False)
245
+ security = relationship('Security', foreign_keys=[security_id],
246
+ backref='transactions')
247
+ units = Column(Numeric)
248
+
249
+
250
+ # Import
251
+ client = OFXClient('https://ofxs.ameritrade.com/cgi-bin/apps/OFX',
252
+ org='Ameritrade Technology Group', fid='AIS',
253
+ brokerid='ameritrade.com')
254
+ stmtrq = InvStmtRq(acctid='999999999')
255
+ response = client.request_statements(user='elmerfudd',
256
+ password='T0PS3CR3T', invstmtrqs=[stmtrq])
257
+ parser = OFXTree()
258
+ parser.parse(response)
259
+ ofx = parser.convert()
260
+
261
+
262
+ # Extract
263
+ def make_security(secinfo):
264
+ return Security(
265
+ name=secinfo.secname, ticker=secinfo.ticker,
266
+ uniqueidtype=secinfo.uniqueidtype, uniqueid=secinfo.uniqueid)
267
+
268
+
269
+ securities = {(sec.uniqueidtype, sec.uniqueid): make_security(sec)
270
+ for sec in ofx.securities}
271
+
272
+
273
+ stmt = ofx.statements[0]
274
+ account = Account(brokerid=stmt.brokerid, number=stmt.acctid)
275
+
276
+
277
+ def make_trade(invtran):
278
+ security = securities[(invtran.uniqueidtype, invtran.uniqueid)]
279
+ return Transaction(
280
+ uniqueid=invtran.fitid, datetime=invtran.dttrade,
281
+ dtsettle=invtran.dtsettle, type='trade', memo=invtran.memo,
282
+ currency=invtran.currency, cash=invtran.total, account=account,
283
+ security=security, units=invtran.units)
284
+
285
+
286
+ trades = [make_trade(tx) for tx in stmt.transactions
287
+ if isinstance(tx, (BUYSTOCK, SELLSTOCK))] # dispatch by model class
288
+
289
+
290
+ # Persist
291
+ engine = create_engine('')
292
+ Session = sessionmaker(bind=engine)
293
+ session = Session()
294
+ session.add(account)
295
+ session.add_all(securities.values())
296
+ session.add_all(trades)
297
+ session.commit()
298
+
174
299
  Contributing
175
300
  ============
176
301
 
@@ -181,16 +306,20 @@ clone the repository:
181
306
 
182
307
  git clone https://github.com/csingley/ofxtools.git
183
308
 
184
- Feel free to `create pull requests`_ on `ofxtools repository on GitHub`_.
309
+ Set up a `virtual environment`_, and install the package in development mode
310
+ so you're working on live code:
185
311
 
186
- Again, the minimal dependencies make it simple to install with the Python user
187
- installation scheme:
312
+ ::
313
+
314
+ python setup.py develop
315
+
316
+ Install all development requirements:
188
317
 
189
318
  ::
190
319
 
191
- python setup.py develop --user
320
+ pip install -r requirements-development.txt
192
321
 
193
- However, you'll want to run the tests, either with ``make``:
322
+ Run the tests, either with ``make``:
194
323
 
195
324
  ::
196
325
 
@@ -200,18 +329,10 @@ or directly with ``nosetests``:
200
329
 
201
330
  ::
202
331
 
203
- nosetests -dsv --with-yanc --with-coverage --cover-package ofxtools
204
-
205
-
206
- if you don't already have `nose`, `coverage`, etc. installed, and you don't
207
- want to clutter your system libraries just for this work, you can create a
208
- `virtual environment`_ and install all development requirements:
332
+ nosetests -dsv --with-coverage --cover-package ofxtools
209
333
 
210
- ::
334
+ Feel free to `create pull requests`_ on `ofxtools repository on GitHub`_.
211
335
 
212
- virtualenv .venv
213
- source .venv/bin/activate
214
- pip install -r requirements-development.txt
215
336
 
216
337
  Resources
217
338
  =========
@@ -226,10 +347,11 @@ Resources
226
347
  .. _Requests: http://docs.python-requests.org/en/master/
227
348
  .. _PyPI: https://pypi.python.org/pypi/ofxtools
228
349
  .. _current master: https://github.com/csingley/ofxtools/archive/master.zip
350
+ .. _virtual environment: https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments
229
351
  .. _OFX spec: http://www.ofx.net/downloads.html
230
352
  .. _Git: https://git-scm.com/
231
353
  .. _create pull requests: https://help.github.com/articles/using-pull-requests/
232
354
  .. _ofxtools repository on GitHub: https://github.com/csingley/ofxtools
233
- .. _virtual environment: http://docs.python-guide.org/en/latest/dev/virtualenvs/
234
355
  .. _Quicken data mapping guide: https://fi.intuit.com/downloads/QW_DataMappingGuide.pdf
235
356
  .. _OFX Home: http://www.ofxhome.com/
357
+