Skip to content
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

add script to store budget offline and re-create a client from this offline data #60

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@ python:
- 3.4
- 3.5
- 3.6
- 3.7
install:
- PACKAGE_VERSION=`python setup.py --version`
- TAG_NAME=v$PACKAGE_VERSION
- pip install --upgrade pip
- pip install .
- pip install -r requirements.txt
- pip install -r test_requirements.txt
- pipenv install --dev
- pipenv install -e .
before_install:
- export TRAVIS_COMMIT_MESSAGE=$(git log --format=%B -n 1 $TRAVIS_COMMIT)
- echo "$TRAVIS_COMMIT_MESSAGE"
- PACKAGE_VERSION=`python setup.py --version`
- TAG_NAME=v$PACKAGE_VERSION
- pip install --upgrade pip
- pip install pipenv
script:
- 'sh test.sh'
- ( if [ -n "$TRAVIS_TAG" ]; then if [ $TAG_NAME != $TRAVIS_TAG ]; then echo "This tag is for the wrong version. Got \"$TRAVIS_TAG\" expected \"$TAG_NAME\"."; exit 1; fi; fi; )
after_success:
- pip install coveralls
- coveralls
- pipenv run coveralls
before_deploy:
# create the documentation
- pip install wheel
- pipenv pip install wheel
deploy:
provider: pypi
user: rienafairefr
Expand Down
27 changes: 27 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[[source]]

url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"


[dev-packages]

mock = "*"
coveralls = "*"
nose = "*"


[packages]

configargparse = "*"
configparser = "*"
requests = "*"
jsontableschema = "==0.10.0"
aenum = "*"
sqlalchemy = "*"
lxml = "==3.8.0"
ofxtools = {ref = "4a3e496d7d2a3babdeabd4e114d98fc5f2862667", git = "https://github.com/csingley/ofxtools.git", editable = true}
pynab = "*"
bcrypt = "*"
"functools32" = "*"
722 changes: 722 additions & 0 deletions Pipfile.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pynYNAB/ClientFactory.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ class Arg(object):pass
if not hasattr(args, 'password') or args.password is None:
raise NoCredentialsException
connection = nYnabConnection(args.email, args.password)
connection.init_session()
else:
connection = args.connection

connection.init_session()
client_id = connection.id

def postprocessed_client(cl):
Expand Down
3 changes: 3 additions & 0 deletions tests/test_persist.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ class MockConnection(object):
def __init__(self,id):
self.id = id

def init_session(self):
pass


class Args(object):
budget_name = 'Test Budget'
Expand Down
4 changes: 4 additions & 0 deletions tests/tests_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
class MockConnection2(object):
id='12345'

def init_session(self): pass

factory = nYnabClientFactory('sqlite://')


Expand All @@ -38,6 +40,8 @@ def dorequest(this,request_dic, opname):
user_id = '1234'
id = '1234'

def init_session(self): pass

self.client = factory.create_client(budgetname='', nynabconnection=MockConnection2(), sync=False)
self.client.create_budget(budget_name='New Budget')

Expand Down
124 changes: 124 additions & 0 deletions testscripts/offline_budget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import logging
import os

import datetime
from pynYNAB.ClientFactory import nYnabClientFactory
from sqlalchemy import create_engine
import json
import settings


class MockConnection(object):
user_id = '1'
id = '1c1ba2d2-b31e-4b67-a76d-03c47cbf826b'
directory = None

def __init__(self, directory=None):
if directory is not None:
self.directory = directory

def init_session(self):
pass

def dorequest(self, request_dic, opname):
p = '{}/{}.json'.format(self.directory, opname)
if not os.path.exists(p):
return None
with open(p, 'r') as f:
data = json.load(f)
return data


class nYnabOfflineClient(object):
def __new__(cls, *args, **kwargs):
connection = kwargs.pop('nynabconnection', None)

class Args(object):
budget_name = kwargs.pop('budgetname', None)
email = connection.email if hasattr(connection, 'email') else kwargs.pop('email', '')
password = connection.password if hasattr(connection, 'password') else kwargs.pop('password', '')
nynabconnection = connection
db_path = 'offline'

passed = Args()
if hasattr(passed, 'db_path'):
logging.info('Creating client from server...')
factory = nYnabClientFactory(
engine=create_engine('sqlite:///{}/{}.db'.format(passed.db_path, settings.ynab_budget)))
else:
logging.info('Creating client from database...')
factory = nYnabClientFactory(engine=create_engine('sqlite:///:memory:'))
return factory.create_client(passed, sync=False)


class OfflineBudget:
directory = 'offline'

def __init__(self, action='load'):
# create directory where to store the offline budget
self.client = None
try:
os.mkdir(self.directory)
except OSError as e:
if e.errno == 17:
pass
else:
raise e

if action == 'load':
self.client = self.load_offline_client()
else:
self.sync_offline_client()

def write_file(self, client, entity):
a = getattr(client, entity)
with open('{}/{}-{}.json'.format(self.directory, entity, settings.ynab_budget), 'w') as f:
data = a.get_dict()
logging.info('Writing {}: {}'.format(entity, data))
json.dump(data, f)

def read_file(self, entity):
with open('{}/{}-{}.json'.format(self.directory, entity, settings.ynab_budget), 'r') as f:
data = json.load(f)
logging.info('Found {}: {}'.format(entity, data))
return data

def sync_offline_client(self):
client = nYnabOfflineClient(email=settings.ynab_username, password=settings.ynab_password,
budgetname=settings.ynab_budget,
logger=settings.log, db_path=self.directory)
if os.path.exists('{}/db-{}.db'.format(self.directory, settings.ynab_budget)):
try:
self.read_file('budget')
self.read_file('catalog')
logging.warn('Old offline budget found. Skipping...')
return
except (ValueError, IOError) as e:
logging.info('Error parsing offline files: {}'.format(e.message))

client.sync()
self.write_file(client, 'budget')
self.write_file(client, 'catalog')

def load_offline_client(self):
try:
self.client = self._load()
except (IOError, AttributeError, ValueError) as e:
self.sync_offline_client()
self.client = self._load()

logging.debug('Loaded offline client')
return self.client

def _load(self):
client = nYnabOfflineClient(email=settings.ynab_username, password=settings.ynab_password,
budgetname=settings.ynab_budget,
logger=settings.log, nynabconnection=MockConnection(directory=self.directory))
client.budget.from_dict(self.read_file('budget'))
client.catalog.from_dict(self.read_file('catalog'))
return client


if __name__ == '__main__':
OfflineBudget(action='load')