From 581f3c5d9ea22ed5717eba1b9d7be6cb04f16f36 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Sat, 13 Jan 2018 06:35:38 +0000 Subject: [PATCH 01/20] adding underlying base classs --- nessie/models/transaction.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 nessie/models/transaction.py diff --git a/nessie/models/transaction.py b/nessie/models/transaction.py new file mode 100644 index 0000000..e0c7386 --- /dev/null +++ b/nessie/models/transaction.py @@ -0,0 +1,7 @@ +# underlying base class +# should not be directly used + + +class Transaction(): + def __init__(self, _json): + pass \ No newline at end of file From a52f9fd2bdde17d9689796e36caee12cc0999eb3 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Sat, 13 Jan 2018 06:36:31 +0000 Subject: [PATCH 02/20] add transaction base class --- nessie/transactionRequests.py | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 nessie/transactionRequests.py diff --git a/nessie/transactionRequests.py b/nessie/transactionRequests.py new file mode 100644 index 0000000..2612493 --- /dev/null +++ b/nessie/transactionRequests.py @@ -0,0 +1,66 @@ +# base class transaction +# should not be directly used +import requests +from nessie import utils + +""" + Where transaction is a: + bill + deposit + loan + purchase + transfer + withdrawal + + accounts//s + GET fetch all transaction + POST create new transaction under + + transaction/ + GET fetch selected transaction + PUT update selected transaction + DELETE delete selected transaction +""" + +class transactionRequest(): + def __init__(self, api_key, transaction_name:str): + self.key = api_key + self.base_url = utils.constants.baseUrl + self.transaction = transaction_name + + # creates under the provided account + def _create_transaction(self, account_id): + url = f'{self.base_url}/{account_id}/{self.transaction}?key={self.key}' + response = requests.post(url) + result = response.json() + return result + + # return list of python objects from account + def _get_account_transactions(self, account_id): + url = f'{self.base_url}/accounts/{account_id}/{self.transaction}?key={self.key}' + response = requests.get(url) + result = response.json() + + # need to do work here to convert json into objects + + def _get_transaction(self, transaction_id): + url = f'{self.base_url}/{self.transaction}/{transaction_id}?key={self.key}' + response = requests.get(url) + result = response.json() + return result + + def _update_transaction(self, transaction_id): + url = f'{self.base_url}/{self.transaction}/{transaction_id}?key={self.key}' + response = requests.put(url) + result = response.json() + return result + + def _delete_transaction(self, transaction_id): + url = f'{self.base_url}/{self.transaction}/{transaction_id}?key={self.key}' + response = requests.delete(url) + result = response.json() + return result + + + + \ No newline at end of file From ff4ba3baf2d95a7cc3f2f7cc7e3fc364e6e3e30a Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Sat, 13 Jan 2018 06:58:48 +0000 Subject: [PATCH 03/20] add client with api key --- nessie/client.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 nessie/client.py diff --git a/nessie/client.py b/nessie/client.py new file mode 100644 index 0000000..a27cb36 --- /dev/null +++ b/nessie/client.py @@ -0,0 +1,11 @@ +import os + +class Client(): + def __init__(self, nessie_api_key=None): + # if no key is set then fetch from environment + if nessie_api_key is None: + self.key = os.environ['NESSIE_API_KEY'] + else: + self.key = nessie_api_key + + \ No newline at end of file From 9543bc6d7480b6e5e895bccdc1a8250bfd58d874 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Sat, 13 Jan 2018 13:13:53 +0000 Subject: [PATCH 04/20] adding client --- nessie/client.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nessie/client.py b/nessie/client.py index a27cb36..0649661 100644 --- a/nessie/client.py +++ b/nessie/client.py @@ -1,4 +1,5 @@ import os +from nessie.customerRequests import customerRequests class Client(): def __init__(self, nessie_api_key=None): @@ -8,4 +9,7 @@ def __init__(self, nessie_api_key=None): else: self.key = nessie_api_key - \ No newline at end of file + + + def get_customers(self): + \ No newline at end of file From 426b3efe7921154b53674de5ff018372a6c61845 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Sat, 13 Jan 2018 22:05:40 +0000 Subject: [PATCH 05/20] updtae pylint --- .pylintrc | 407 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 .pylintrc diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..10fe4c3 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,407 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Allow optimization of some AST trees. This will activate a peephole AST +# optimizer, which will apply various small optimizations. For instance, it can +# be used to obtain the result of joining multiple strings with the addition +# operator. Joining a lot of strings can lead to a maximum recursion error in +# Pylint and this flag can prevent that. It has one side effect, the resulting +# AST will be different than the one from reality. This option is deprecated +# and it will be removed in Pylint 2.0. +optimize-ast=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=invalid-name,blacklisted-name,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,cyclic-import,missing-docstring,empty-docstring,unneeded-not,no-absolute-import,old-division,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,bad-mcs-classmethod-argument,consider-using-enumerate,consider-iterating-dictionary,bad-classmethod-argument,bad-mcs-method-argument,suppressed-message,useless-suppression,too-many-statements,too-many-locals,too-many-boolean-expressions,too-many-return-statements,too-many-arguments,too-many-branches,ungrouped-imports,duplicate-code,old-style-class,too-many-public-methods,too-many-instance-attributes,too-few-public-methods,too-many-ancestors,redefined-variable-type,no-self-use,no-staticmethod-decorator,no-classmethod-decorator,trailing-newlines,missing-final-newline,line-too-long,trailing-whitespace,too-many-lines,using-cmp-argument,wrong-import-order,multiple-imports,wrong-import-position,unexpected-line-ending-format,import-star-module-level,old-octal-literal,unidiomatic-typecheck,misplaced-comparison-constant,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,oct-method,reload-builtin,nonzero-method,hex-method,multiple-statements,mixed-line-endings,bad-whitespace,superfluous-parens,wrong-spelling-in-docstring,invalid-characters-in-docstring,singleton-comparison,wrong-spelling-in-comment,bad-continuation,input-builtin,round-builtin,cmp-method,map-builtin-not-iterating,zip-builtin-not-iterating,intern-builtin,unichr-builtin,range-builtin-not-iterating,filter-builtin-not-iterating,simplifiable-if-statement,too-many-nested-blocks + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". This option is deprecated +# and it will be removed in Pylint 2.0. +files-output=no + +# Tells whether to display a full report or only the messages +reports=yes + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=100 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,future.builtins + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[BASIC] + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[ELIF] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception From 8c48a3640d73f9c5aff1583f1d83f2e9a4260615 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Sat, 13 Jan 2018 22:08:45 +0000 Subject: [PATCH 06/20] add pointless string statement to ignore --- .pylintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 10fe4c3..98ed419 100644 --- a/.pylintrc +++ b/.pylintrc @@ -65,7 +65,7 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -disable=invalid-name,blacklisted-name,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,cyclic-import,missing-docstring,empty-docstring,unneeded-not,no-absolute-import,old-division,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,bad-mcs-classmethod-argument,consider-using-enumerate,consider-iterating-dictionary,bad-classmethod-argument,bad-mcs-method-argument,suppressed-message,useless-suppression,too-many-statements,too-many-locals,too-many-boolean-expressions,too-many-return-statements,too-many-arguments,too-many-branches,ungrouped-imports,duplicate-code,old-style-class,too-many-public-methods,too-many-instance-attributes,too-few-public-methods,too-many-ancestors,redefined-variable-type,no-self-use,no-staticmethod-decorator,no-classmethod-decorator,trailing-newlines,missing-final-newline,line-too-long,trailing-whitespace,too-many-lines,using-cmp-argument,wrong-import-order,multiple-imports,wrong-import-position,unexpected-line-ending-format,import-star-module-level,old-octal-literal,unidiomatic-typecheck,misplaced-comparison-constant,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,oct-method,reload-builtin,nonzero-method,hex-method,multiple-statements,mixed-line-endings,bad-whitespace,superfluous-parens,wrong-spelling-in-docstring,invalid-characters-in-docstring,singleton-comparison,wrong-spelling-in-comment,bad-continuation,input-builtin,round-builtin,cmp-method,map-builtin-not-iterating,zip-builtin-not-iterating,intern-builtin,unichr-builtin,range-builtin-not-iterating,filter-builtin-not-iterating,simplifiable-if-statement,too-many-nested-blocks +disable=pointless-string-statement,invalid-name,blacklisted-name,raw_input-builtin,long-builtin,file-builtin,execfile-builtin,coerce-builtin,cmp-builtin,buffer-builtin,basestring-builtin,apply-builtin,cyclic-import,missing-docstring,empty-docstring,unneeded-not,no-absolute-import,old-division,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,bad-mcs-classmethod-argument,consider-using-enumerate,consider-iterating-dictionary,bad-classmethod-argument,bad-mcs-method-argument,suppressed-message,useless-suppression,too-many-statements,too-many-locals,too-many-boolean-expressions,too-many-return-statements,too-many-arguments,too-many-branches,ungrouped-imports,duplicate-code,old-style-class,too-many-public-methods,too-many-instance-attributes,too-few-public-methods,too-many-ancestors,redefined-variable-type,no-self-use,no-staticmethod-decorator,no-classmethod-decorator,trailing-newlines,missing-final-newline,line-too-long,trailing-whitespace,too-many-lines,using-cmp-argument,wrong-import-order,multiple-imports,wrong-import-position,unexpected-line-ending-format,import-star-module-level,old-octal-literal,unidiomatic-typecheck,misplaced-comparison-constant,print-statement,unpacking-in-except,parameter-unpacking,backtick,old-raise-syntax,old-ne-operator,long-suffix,dict-view-method,dict-iter-method,metaclass-assignment,next-method-called,raising-string,indexing-exception,oct-method,reload-builtin,nonzero-method,hex-method,multiple-statements,mixed-line-endings,bad-whitespace,superfluous-parens,wrong-spelling-in-docstring,invalid-characters-in-docstring,singleton-comparison,wrong-spelling-in-comment,bad-continuation,input-builtin,round-builtin,cmp-method,map-builtin-not-iterating,zip-builtin-not-iterating,intern-builtin,unichr-builtin,range-builtin-not-iterating,filter-builtin-not-iterating,simplifiable-if-statement,too-many-nested-blocks [REPORTS] From 26fd472980a68521c5acb7456b99e4e0c499f127 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Sat, 13 Jan 2018 22:43:05 +0000 Subject: [PATCH 07/20] adding client and fixing imports --- nessie/client.py | 10 ++++++---- nessie/customerRequests.py | 7 ++++--- nessie/models/customer.py | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/nessie/client.py b/nessie/client.py index 0649661..9e30f2f 100644 --- a/nessie/client.py +++ b/nessie/client.py @@ -1,5 +1,8 @@ import os -from nessie.customerRequests import customerRequests +from nessie.customerRequests import CustomerRequests +from nessie.accountRequests import AccountRequests + +from nessie.billRequests import BillRequest class Client(): def __init__(self, nessie_api_key=None): @@ -9,7 +12,6 @@ def __init__(self, nessie_api_key=None): else: self.key = nessie_api_key - - - def get_customers(self): + self.account = AccountRequests(self.key) + self.bill = BillRequest(self.key) \ No newline at end of file diff --git a/nessie/customerRequests.py b/nessie/customerRequests.py index f973064..105a17b 100644 --- a/nessie/customerRequests.py +++ b/nessie/customerRequests.py @@ -1,9 +1,10 @@ import requests -import utils.constants import json import re -from models.customer import Customer -from utils.exceptions import CustomerValidationError, NessieApiError, AddressValidationError + +from nessie.utils import constants +from nessie.models.customer import Customer +from nessie.utils.exceptions import CustomerValidationError, NessieApiError, AddressValidationError class CustomerRequests: diff --git a/nessie/models/customer.py b/nessie/models/customer.py index 43f5df9..854dd55 100644 --- a/nessie/models/customer.py +++ b/nessie/models/customer.py @@ -1,4 +1,4 @@ -from models.address import Address +from nessie.models.address import Address class Customer: From 0b92abae1ed07997081f3d579540399c35ae2453 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Sun, 14 Jan 2018 14:00:34 +0000 Subject: [PATCH 08/20] added NESSIE_API_KEY and test_client --- .travis.yml | 16 ++++++++-------- tests/test_client.py | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 tests/test_client.py diff --git a/.travis.yml b/.travis.yml index d94a2eb..80c1a0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ language: python python: - - "3.6" -# need to refactor to requirements/ setup +- '3.6' install: - - pip install pipenv - - pipenv install --dev +- pip install pipenv +- pipenv install --dev script: -# have pylint only show warnings and errors -# and ignore regular syntax errors - - pylint --disable=R,C nessie - - python -m unittest \ No newline at end of file +- pylint --disable=R,C nessie +- python -m unittest +env: + global: + secure: kxSk6tcEhkvodjtDWCeJf/qI/vpRptfGZ6UmZ2G9GbHizXIVFleEmDmIZyWNnqRqv/ugdomlQhif0FRGod/e73MoIV9qa7kGWxuhExOhWzTo8tz0NzyyqLAFTmw5IB8m09H6MhJY9VpPygbpN0aWjOrrKdxRsj0ocVXPn3M62je6Om2ndSjMbynWrYutrhtijcp3BVka2vvjy6iNt9i0ZK/M0dsqqnuEgXe5uL4xKcmpvWu56QYcRhNky6qzxhh3Y1pyoBF7fA7fH2EnECCpnJaBFrdQFJzJ7VNAdoztX15G1E5KSudJu+qnKEw91RoQz9F9lmJgJJlJnYYMrjAqIE1h6eS560vFU1UGUZs1MU+FAWmRS1V09l+YKEtfmXg6NOO8tyzMuOEj1opwA95q1j17Ffg7E3SEs38ICpQYuK3LZUTlXELVsfPizR+70CQFDzWjI/OTIo6xi1gE1gWYUo3bHXIAn5jCJQiWNxMkaKavE+YXj/zWePJIeWlWbx1ZV0kZrhJ+V7Prlh86VYFPyI/jPdj+6Jc8IbvxDtsvCn2WZiHNJqtBTlcTT+kN5WShbq5bC+fMa++uffVe1nFy/cFEMaUX+tN2r/puzSPn4YCZ8BAHOuSKbUMEVk6j8ZKDBzqCMPxoYwFHdrrlbFC+lqEj38Z3+odV9Ni4CrquiUA= diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 0000000..5901d33 --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,15 @@ +import unittest +import sys, os +path = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0,path+'/../') + +from nessie.client import Client + +class TestClient(unittest.TestCase): + + def test_client_initialize(self): + # should implicitly retrieve key from + # env.NESSIE_API_KEY + client = Client() + + self.assertIsNotNone(client.key) \ No newline at end of file From 7ed48745f5d50c633e496a283fed4c9a8f78981f Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Tue, 16 Jan 2018 20:10:04 +0000 Subject: [PATCH 09/20] adding client --- nessie/billRequests.py | 7 +------ nessie/client.py | 4 ++++ tests/test_bill_requests.py | 15 +++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/nessie/billRequests.py b/nessie/billRequests.py index 34c8aea..0000a85 100644 --- a/nessie/billRequests.py +++ b/nessie/billRequests.py @@ -70,9 +70,4 @@ def delete_bill(self, bill_id): def error_handle(error_response): - raise Exception(error_response.json()) - -b = BillRequest('24bb950537c1164a2fbb1bf2a37c3267') -bi = b.get_bill("5a261c3883a71c405074fcbd") -# r = b.get_customer_bills("5a2614e483a71c405074fcba") -# print(r) \ No newline at end of file + raise Exception(error_response.json()) \ No newline at end of file diff --git a/nessie/client.py b/nessie/client.py index 9e30f2f..9561a9a 100644 --- a/nessie/client.py +++ b/nessie/client.py @@ -2,6 +2,8 @@ from nessie.customerRequests import CustomerRequests from nessie.accountRequests import AccountRequests +from nessie.dataRequests import DataRequest + from nessie.billRequests import BillRequest class Client(): @@ -14,4 +16,6 @@ def __init__(self, nessie_api_key=None): self.account = AccountRequests(self.key) self.bill = BillRequest(self.key) + self.data = DataRequest(self.key) + \ No newline at end of file diff --git a/tests/test_bill_requests.py b/tests/test_bill_requests.py index 61c3afb..382a0d0 100644 --- a/tests/test_bill_requests.py +++ b/tests/test_bill_requests.py @@ -4,14 +4,14 @@ sys.path.insert(0,path+'/../') from nessie.accountRequests import AccountRequests -from nessie import billRequests +from nessie.billRequests import BillRequest from nessie.dataRequests import DataRequest +from nessie.client import Client # def test_create_bill(self): # bill_factory = billRequests.BillRequest("wkey") -wkey = '7e9b72fdb7b286fcd0aae87deb0e09a2' # customer_id = '5a546ffd6514d52c7774a2ca' # account_factory = AccountRequests(wkey) @@ -23,7 +23,10 @@ class TestBillRequests(unittest.TestCase): # create some dummy bills def setUp(self): - bill_factory = billRequests.BillRequest(wkey) + # implicitly get NESSIE_API_KEY from env + self.client = Client() + + bill_factory = self.client.bill bill = bill_factory.create_bill(account_id, status='pending', payee='bobby', @@ -34,12 +37,12 @@ def setUp(self): ) def tearDown(self): - data_deletor = DataRequest(wkey) + data_deletor = client.data response = data_deletor.delete_data('Bills') def test_get_bill_succeed(self): print("test_get_bill_succeed") - bill_factory = billRequests.BillRequest(wkey) + bill_factory = self.client.bill result = bill_factory.get_account_bills(account_id) print(result) # result = bill_factory.get_bill("5a261c3883a71c405074fcbd") @@ -49,7 +52,7 @@ def test_get_bill_succeed(self): # try fetching a bill that doesn't exist def test_get_nonreal_bill_fail(self): print("test_get_nonreal_bill_fail") - bill_factory = billRequests.BillRequest(wkey) + bill_factory = self.client.bill result = bill_factory.get_bill("fake") expected_result = {'code':404, 'message':'Invalid ID'} From edb19a4f27052800deaf72a66c81248e23557913 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Tue, 30 Jan 2018 01:31:37 +0000 Subject: [PATCH 10/20] fix headers and dataRequests --- nessie/client.py | 12 +++++------ nessie/customerRequests.py | 13 ++++++----- nessie/dataRequests.py | 16 ++++++++++++-- nessie/transactionRequests.py | 6 ++++-- tests/test_bill_requests.py | 15 ++++++++----- tests/test_customer_requests.py | 38 +++++++++++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 tests/test_customer_requests.py diff --git a/nessie/client.py b/nessie/client.py index bde210c..2bd8cc0 100644 --- a/nessie/client.py +++ b/nessie/client.py @@ -1,10 +1,9 @@ import os -from nessie.customerRequests import CustomerRequests -from nessie.accountRequests import AccountRequests - -from nessie.dataRequests import DataRequests - -from nessie.billRequests import BillRequest +# ordered from highest to lowest scope +from .dataRequests import DataRequests +from .customerRequests import CustomerRequests +from .accountRequests import AccountRequests +from .billRequests import BillRequest class Client(): def __init__(self, nessie_api_key=None): @@ -20,5 +19,6 @@ def __init__(self, nessie_api_key=None): self.account = AccountRequests(self.key) self.bill = BillRequest(self.key) self.data = DataRequests(self.key) + self.customer = CustomerRequests(self.key) \ No newline at end of file diff --git a/nessie/customerRequests.py b/nessie/customerRequests.py index 7b9becf..6b4749d 100644 --- a/nessie/customerRequests.py +++ b/nessie/customerRequests.py @@ -3,9 +3,9 @@ import re -from nessie.models.customer import Customer -from nessie.utils.exceptions import CustomerValidationError, NessieApiError, AddressValidationError -from nessie import utils +from .models.customer import Customer +from .utils.exceptions import CustomerValidationError, NessieApiError, AddressValidationError +from . import utils class CustomerRequests: @@ -57,7 +57,6 @@ def get_customer_by_id(self, customer_id): def create_customer(self, first_name: str, last_name: str, address): if first_name is None or last_name is None: raise CustomerValidationError(utils.constants.createCustomerMissingFields) - val_address = validate_address(address) if val_address != utils.constants.success: raise AddressValidationError(val_address) @@ -67,7 +66,7 @@ def create_customer(self, first_name: str, last_name: str, address): body = { "first_name": first_name, "last_name": last_name, - "address": address.to_dict() + "address": address } r = requests.post(utils.constants.customersUrl, headers=header, params=payload, data=json.dumps(body)) if r.status_code != 201: @@ -91,7 +90,7 @@ def update_customer(self, customer_id, new_address): header = {"Content-Type": "application/json"} payload = {"key": self.key} - body = {"address": new_address.to_dict()} + body = {"address": new_address} url = utils.constants.customersIdUrl % customer_id r = requests.put(url, headers=header, params=payload, data=json.dumps(body)) if r.status_code != 202: @@ -103,6 +102,6 @@ def update_customer(self, customer_id, new_address): def validate_address(address): if address is None: return utils.constants.addressMissingField - elif re.fullmatch(r"^[0-9]{5}$", address.zipcode) is None: + elif re.fullmatch(r"^[0-9]{5}$", address['zip']) is None: return utils.constants.addressValidationZipCode return utils.constants.success diff --git a/nessie/dataRequests.py b/nessie/dataRequests.py index 88f0aa2..493048c 100644 --- a/nessie/dataRequests.py +++ b/nessie/dataRequests.py @@ -13,11 +13,23 @@ def __init__(self,api_key): def delete_data(self, dataType:str): url=f'{baseUrl}/data?type={dataType}&key={self.key}' - response = requests.delete(url) + # 'Connection':'close', + headers = { 'Content-type': 'application/json'} + response = requests.delete(url, headers=headers) # status_code 200 denotes success # status_code 404 denotes success, but no data to delete - if((response.status_code != 200) and (response.status_code!= 404)): + if( + (response.status_code != 200) and + (response.status_code != 204) and + (response.status_code != 404)): raise NessieApiError(response) + + # sometimes the response encoding is nothing + # rather than utf-8 so the response.json() + # will crash + if (response.encoding is None): + return {} + result = response.json() return result diff --git a/nessie/transactionRequests.py b/nessie/transactionRequests.py index 2612493..c0aa641 100644 --- a/nessie/transactionRequests.py +++ b/nessie/transactionRequests.py @@ -23,10 +23,11 @@ """ class transactionRequest(): - def __init__(self, api_key, transaction_name:str): + def __init__(self, api_key, transaction_name:str, transaction_class): self.key = api_key self.base_url = utils.constants.baseUrl self.transaction = transaction_name + self.transaction_class = transaction_class # creates under the provided account def _create_transaction(self, account_id): @@ -40,7 +41,8 @@ def _get_account_transactions(self, account_id): url = f'{self.base_url}/accounts/{account_id}/{self.transaction}?key={self.key}' response = requests.get(url) result = response.json() - + + return result # need to do work here to convert json into objects def _get_transaction(self, transaction_id): diff --git a/tests/test_bill_requests.py b/tests/test_bill_requests.py index 0df3345..7e4de24 100644 --- a/tests/test_bill_requests.py +++ b/tests/test_bill_requests.py @@ -21,7 +21,7 @@ # premade account id account_id = '5a5471796514d52c7774a2cb' -class TestBillRequests(unittest.TestCase): +class TestBillRequests(): # create some dummy bills def setUp(self): # implicitly get NESSIE_API_KEY from env @@ -38,8 +38,12 @@ def setUp(self): ) def tearDown(self): - data_deletor = self.client.data - response = data_deletor.delete_data('Bills') + # data_deletor = self.client.data + # response = data_deletor.delete_data('Bills') + d = DataRequests('7e9b72fdb7b286fcd0aae87deb0e09a2') + d.delete_data('Bills') + + # def test_get_bill_succeed(self): # print("test_get_bill_succeed") @@ -53,7 +57,7 @@ def tearDown(self): # try fetching a bill that doesn't exist def test_get_nonreal_bill_fail(self): print("test_get_nonreal_bill_fail") - bill_factory = billRequests.BillRequest(wkey) + bill_factory = self.client.bill expected_status_code = 404 @@ -67,5 +71,6 @@ def test_get_nonreal_bill_fail(self): self.assertEqual(result.code,expected_status_code) - +# d = DataRequests('7e9b72fdb7b286fcd0aae87deb0e09a2') +# d.delete_data('Bills') \ No newline at end of file diff --git a/tests/test_customer_requests.py b/tests/test_customer_requests.py new file mode 100644 index 0000000..f171629 --- /dev/null +++ b/tests/test_customer_requests.py @@ -0,0 +1,38 @@ +import unittest +import sys, os +path = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0,path+'/../') + +from nessie.client import Client +from nessie.customerRequests import CustomerRequests +from nessie.models.customer import Customer + +class TestCustomerRequests(unittest.TestCase): + + def setUp(self): + # implicitly get NESSIE_API_KEY from env + self.client = Client() + + self.client.data.delete_data('Customers') + + self.client.customer.create_customer( + first_name = "Adam", + last_name = "Smith", + address = { + "street_number": "1", + "street_name": "Dolly Madison Blvd", + "city": "Tysons Corner", + "state": "VA", + "zip": "12345" + } + ) + + def tearDown(self): + self.client.data.delete_data('Customers') + + def test_get_customer(self): + customers = self.client.customer.get_all_customers() + + # assert there is one customer + self.assertEqual(len(customers), 1) + self.assertEqual(type(customers[0]), Customer) \ No newline at end of file From bc94a5f8dea056a6e814239f0f1c068d87bd02e3 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Tue, 30 Jan 2018 02:33:20 +0000 Subject: [PATCH 11/20] fix customer equality and comparisons --- nessie/models/address.py | 3 ++ nessie/models/customer.py | 3 ++ tests/test_bill_requests.py | 1 - tests/test_customer_requests.py | 50 ++++++++++++++++++++++++++++++++- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/nessie/models/address.py b/nessie/models/address.py index 3e8b90f..d3fa8b7 100644 --- a/nessie/models/address.py +++ b/nessie/models/address.py @@ -14,3 +14,6 @@ def to_dict(self): "state": self.state, "zip": self.zipcode } + + def __eq__(self, other): + return self.to_dict() == other.to_dict() diff --git a/nessie/models/customer.py b/nessie/models/customer.py index 854dd55..827e516 100644 --- a/nessie/models/customer.py +++ b/nessie/models/customer.py @@ -26,3 +26,6 @@ def to_dict(self): "last_name": self.last_name, "address": self.address.to_dict() } + + def __eq__(self, other): + return self.to_dict() == other.to_dict() diff --git a/tests/test_bill_requests.py b/tests/test_bill_requests.py index 7e4de24..71d8501 100644 --- a/tests/test_bill_requests.py +++ b/tests/test_bill_requests.py @@ -59,7 +59,6 @@ def test_get_nonreal_bill_fail(self): print("test_get_nonreal_bill_fail") bill_factory = self.client.bill - expected_status_code = 404 # expected_message = 'Invalid ID' result = {} diff --git a/tests/test_customer_requests.py b/tests/test_customer_requests.py index f171629..1f99c8f 100644 --- a/tests/test_customer_requests.py +++ b/tests/test_customer_requests.py @@ -35,4 +35,52 @@ def test_get_customer(self): # assert there is one customer self.assertEqual(len(customers), 1) - self.assertEqual(type(customers[0]), Customer) \ No newline at end of file + self.assertEqual(type(customers[0]), Customer) + + def test_create_customer(self): + + customer_json = { + "first_name":"Adam", + "last_name":"Smith", + "address": { + "street_number": "1", + "street_name": "Dolly Madison Blvd", + "city": "Tysons Corner", + "state": "VA", + "zip": "12345" + } + } + + # generated customer from json + expected_customer = Customer(customer_json) + + new_customer = self.client.customer.create_customer( + first_name = "Adam", + last_name = "Smith", + address = { + "street_number": "1", + "street_name": "Dolly Madison Blvd", + "city": "Tysons Corner", + "state": "VA", + "zip": "12345" + } + ) + + # newly created customer id + new_customer_id = new_customer.customer_id + + # the actual customer created and returned + actual_customer = self.client.customer.get_customer_by_id(new_customer_id) + + + + # add customer_id on (its impossible for + # the expected to know the dynamic id) + expected_customer.customer_id = actual_customer.customer_id + + print("expected_customer:") + print(vars(expected_customer)) + print("actual_customer:") + print(vars(actual_customer)) + print("id",expected_customer.customer_id) + self.assertEqual(actual_customer,expected_customer) From 67f7e685cf5bea9a5b2314069873d5be9dc5d6dc Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Tue, 30 Jan 2018 04:10:40 +0000 Subject: [PATCH 12/20] fix customer tests --- nessie/customerRequests.py | 8 +++-- tests/test_customer_requests.py | 57 ++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/nessie/customerRequests.py b/nessie/customerRequests.py index 6b4749d..28f928e 100644 --- a/nessie/customerRequests.py +++ b/nessie/customerRequests.py @@ -80,17 +80,21 @@ def create_customer(self, first_name: str, last_name: str, address): return created_customer # Updates a customer's address based on CustomerId + # weird can only change address not first/last name def update_customer(self, customer_id, new_address): if customer_id is None: raise CustomerValidationError(utils.constants.customerIdMissingField) - + + # needs check because otherwise + # if you set new city (or any one field of address) + # but not the rest it sets the other address fields to none val_address = validate_address(new_address) if val_address != utils.constants.success: raise AddressValidationError(val_address) header = {"Content-Type": "application/json"} payload = {"key": self.key} - body = {"address": new_address} + body = {'address':new_address} url = utils.constants.customersIdUrl % customer_id r = requests.put(url, headers=header, params=payload, data=json.dumps(body)) if r.status_code != 202: diff --git a/tests/test_customer_requests.py b/tests/test_customer_requests.py index 1f99c8f..5662243 100644 --- a/tests/test_customer_requests.py +++ b/tests/test_customer_requests.py @@ -37,7 +37,7 @@ def test_get_customer(self): self.assertEqual(len(customers), 1) self.assertEqual(type(customers[0]), Customer) - def test_create_customer(self): + def test_create_and_customer(self): customer_json = { "first_name":"Adam", @@ -72,15 +72,56 @@ def test_create_customer(self): # the actual customer created and returned actual_customer = self.client.customer.get_customer_by_id(new_customer_id) - - # add customer_id on (its impossible for # the expected to know the dynamic id) expected_customer.customer_id = actual_customer.customer_id - print("expected_customer:") - print(vars(expected_customer)) - print("actual_customer:") - print(vars(actual_customer)) - print("id",expected_customer.customer_id) + # print("expected_customer:") + # print(vars(expected_customer)) + # print("actual_customer:") + # print(vars(actual_customer)) + # print("id",expected_customer.customer_id) self.assertEqual(actual_customer,expected_customer) + + + # create customer bill + # update customer bill + # get customer bill and verify + # delete customer bill + def test_create_update_get_customer(self): + new_customer = self.client.customer.create_customer( + first_name = "Bob", + last_name = "Anderson", + address = { + "street_number": "2", + "street_name": "Dolly Madison Blvd", + "city": "Tysons Corner", + "state": "VA", + "zip": "12345" + } + ) + + # try updating + + customer_id = new_customer.customer_id + + self.client.customer.update_customer( + customer_id, + { + 'street_number': '3', + "street_name": "Dolly Madison Blvd", + "city": "Tysons Corner", + "state": "VA", + "zip": "12345" + } + ) + + customer = self.client.customer.get_customer_by_id(customer_id) + expected_address = { + "street_number": "3", + "street_name": "Dolly Madison Blvd", + "city": "Tysons Corner", + "state": "VA", + "zip": "12345" + } + self.assertEqual(customer.address.to_dict(),expected_address) \ No newline at end of file From 091b49fea9633e7bdffffbc5b14f3c9ab0ace5d5 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Tue, 30 Jan 2018 04:12:52 +0000 Subject: [PATCH 13/20] change nessie to relative imports --- nessie/atmRequests.py | 6 +++--- nessie/branchRequests.py | 6 +++--- tests/test_atm_requests.py | 0 3 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 tests/test_atm_requests.py diff --git a/nessie/atmRequests.py b/nessie/atmRequests.py index 80457a6..d37a5c6 100644 --- a/nessie/atmRequests.py +++ b/nessie/atmRequests.py @@ -1,7 +1,7 @@ import requests -from nessie.models.atm import ATM -from nessie.utils import constants -from nessie.utils.exceptions import ATMValidationError, NessieApiError +from .models.atm import ATM +from .utils import constants +from .utils.exceptions import ATMValidationError, NessieApiError class ATMRequest(object): diff --git a/nessie/branchRequests.py b/nessie/branchRequests.py index 1d64d28..831d0a4 100644 --- a/nessie/branchRequests.py +++ b/nessie/branchRequests.py @@ -1,8 +1,8 @@ import requests -from nessie.models.branch import Branch -from nessie.utils import constants -from nessie.utils.exceptions import NessieApiError, BranchValidationError +from .models.branch import Branch +from .utils import constants +from .utils.exceptions import NessieApiError, BranchValidationError class BranchRequest(object): diff --git a/tests/test_atm_requests.py b/tests/test_atm_requests.py new file mode 100644 index 0000000..e69de29 From 184988d8e69d36e007b7a598a298edd2e11307a7 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Tue, 30 Jan 2018 15:28:24 +0000 Subject: [PATCH 14/20] add atm tests --- nessie/atmRequests.py | 2 +- nessie/client.py | 12 ++++-- tests/test_atm_requests.py | 74 +++++++++++++++++++++++++++++++++++++ tests/test_bill_requests.py | 11 +----- 4 files changed, 84 insertions(+), 15 deletions(-) diff --git a/nessie/atmRequests.py b/nessie/atmRequests.py index d37a5c6..1746d62 100644 --- a/nessie/atmRequests.py +++ b/nessie/atmRequests.py @@ -39,7 +39,7 @@ def __validateParams(self, req): if (paramsInvalid): raise ATMValidationError(constants.atmInvalidFields) - def getAtms(self, lat=None, lng=None, rad=None): + def get_atms(self, lat=None, lng=None, rad=None): reqUrl = "%s/atms" % self.baseUrl par = self.__buildParams(lat, lng, rad) self.__validateParams(par) diff --git a/nessie/client.py b/nessie/client.py index 2bd8cc0..cca7c75 100644 --- a/nessie/client.py +++ b/nessie/client.py @@ -1,9 +1,11 @@ import os -# ordered from highest to lowest scope -from .dataRequests import DataRequests -from .customerRequests import CustomerRequests + from .accountRequests import AccountRequests +from .atmRequests import ATMRequest from .billRequests import BillRequest +from .branchRequests import BranchRequest +from .customerRequests import CustomerRequests +from .dataRequests import DataRequests class Client(): def __init__(self, nessie_api_key=None): @@ -15,9 +17,11 @@ def __init__(self, nessie_api_key=None): raise Exception(e,"probably need to `export NESSIE_API_KEY=xxxxxxxxxxx`") else: self.key = nessie_api_key - + self.account = AccountRequests(self.key) + self.atm = ATMRequest(self.key) self.bill = BillRequest(self.key) + self.branch = BranchRequest(self.key) self.data = DataRequests(self.key) self.customer = CustomerRequests(self.key) diff --git a/tests/test_atm_requests.py b/tests/test_atm_requests.py index e69de29..695c633 100644 --- a/tests/test_atm_requests.py +++ b/tests/test_atm_requests.py @@ -0,0 +1,74 @@ +import unittest +import sys, os +path = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0,path+'/../') + +from nessie.client import Client + +class TestAtmRequests(unittest.TestCase): + + def setUp(self): + # implicitly get NESSIE_API_KEY from env + self.client = Client() + + def test_get_atms(self): + lat = 38.9283 + lng = -77.1753 + rad = 1 + + observed_atms = self.client.atm.get_atms(lat,lng,rad) + print(observed_atms) + self.assertEqual(1,0) + + expected_firsttwo_atms = [ + { + "_id": "56c66be5a73e492741506f4b", + "name": "McLean 1", + "geocode": { + "lng": -77.17829449999999, + "lat": 38.932887 + }, + "accessibility": 'true', + "hours": [ + "24 hours a day, 7 days a week" + ], + "address": { + "state": "VA", + "zip": "22101", + "city": "McLean", + "street_name": "Chain Bridge Road", + "street_number": "1439" + }, + "language_list": [ + "English" + ], + "amount_left": 273775 + }, + { + "_id": "56c66be5a73e492741506f4c", + "name": "McLean 2", + "geocode": { + "lng": -77.17829449999999, + "lat": 38.932887 + }, + "accessibility": 'false', + "hours": [ + "24 hours a day, 7 days a week" + ], + "address": { + "state": "VA", + "zip": "22101", + "city": "McLean", + "street_name": "Chain Bridge Road", + "street_number": "1439" + }, + "language_list": [ + "Portuguese", + "Korean", + "Spanish", + "Chinese", + "French", + "English" + ], + "amount_left": 444425 + }] \ No newline at end of file diff --git a/tests/test_bill_requests.py b/tests/test_bill_requests.py index 71d8501..3a75213 100644 --- a/tests/test_bill_requests.py +++ b/tests/test_bill_requests.py @@ -14,12 +14,6 @@ # bill_factory = billRequests.BillRequest("wkey") -# customer_id = '5a546ffd6514d52c7774a2ca' -# account_factory = AccountRequests(wkey) -# account_factory.createCustomerAccount(customer_id) - -# premade account id -account_id = '5a5471796514d52c7774a2cb' class TestBillRequests(): # create some dummy bills @@ -68,8 +62,5 @@ def test_get_nonreal_bill_fail(self): result = e self.assertEqual(result.code,expected_status_code) - - -# d = DataRequests('7e9b72fdb7b286fcd0aae87deb0e09a2') -# d.delete_data('Bills') + \ No newline at end of file From e24fa40d85fdb26cd7f8b5035223eec42aaa44f7 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Thu, 1 Feb 2018 04:41:31 +0000 Subject: [PATCH 15/20] merge --- nessie/accountRequests.py | 4 ++-- nessie/utils/exceptions.py | 2 +- tests/test_atm_requests.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nessie/accountRequests.py b/nessie/accountRequests.py index 89dda61..e95fb58 100644 --- a/nessie/accountRequests.py +++ b/nessie/accountRequests.py @@ -1,6 +1,6 @@ import requests, json, urlConstants -from nessie.models.account import Account -from nessie.utils.exceptions import NessieApiError +from .models.account import Account +from .utils.exceptions import NessieApiError class AccountRequests: def __init__(self, apiKey): diff --git a/nessie/utils/exceptions.py b/nessie/utils/exceptions.py index 7de02e5..73166eb 100644 --- a/nessie/utils/exceptions.py +++ b/nessie/utils/exceptions.py @@ -1,4 +1,4 @@ -from nessie.utils import constants +from . import constants class ATMValidationError(Exception): def __init__(self, code): diff --git a/tests/test_atm_requests.py b/tests/test_atm_requests.py index 695c633..118ff20 100644 --- a/tests/test_atm_requests.py +++ b/tests/test_atm_requests.py @@ -18,8 +18,6 @@ def test_get_atms(self): observed_atms = self.client.atm.get_atms(lat,lng,rad) print(observed_atms) - self.assertEqual(1,0) - expected_firsttwo_atms = [ { "_id": "56c66be5a73e492741506f4b", @@ -71,4 +69,6 @@ def test_get_atms(self): "English" ], "amount_left": 444425 - }] \ No newline at end of file + }] + + self.assertEqual(observed_atms,expected_atms) \ No newline at end of file From 12951542b0bbd605858c09b8d95b2625aa0ff51f Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Thu, 1 Feb 2018 06:57:33 +0000 Subject: [PATCH 16/20] fix test atm requests --- nessie/atmRequests.py | 3 +- nessie/models/atm.py | 2 +- tests/test_atm_requests.py | 110 +++++++++++++++++++++++-------------- 3 files changed, 73 insertions(+), 42 deletions(-) diff --git a/nessie/atmRequests.py b/nessie/atmRequests.py index 1746d62..3729d46 100644 --- a/nessie/atmRequests.py +++ b/nessie/atmRequests.py @@ -50,6 +50,7 @@ def get_atms(self, lat=None, lng=None, rad=None): jsonAtms = r.json() while ('next' in r.json()['paging']): + print(r.json()) reqUrl = "%s%s" % (self.baseUrl, r.json()['paging']['next']) r = requests.get(reqUrl) @@ -60,7 +61,7 @@ def get_atms(self, lat=None, lng=None, rad=None): return self.__formatResponse(jsonAtms) - def getAtmById(self, idCode): + def get_atm(self, idCode): reqUrl = "%s/atms/%s" % (self.baseUrl, idCode) par = {'key': self.key} diff --git a/nessie/models/atm.py b/nessie/models/atm.py index be22b76..a1fef78 100644 --- a/nessie/models/atm.py +++ b/nessie/models/atm.py @@ -10,7 +10,7 @@ def __init__(self, jsonData): self.hours = jsonData.get('hours') self.geocode = jsonData.get('geocode') - def toDict(self): + def to_dict(self): returnDict = {} returnDict['_id'] = self.atmId returnDict['name'] = self.name diff --git a/tests/test_atm_requests.py b/tests/test_atm_requests.py index 118ff20..e0346e8 100644 --- a/tests/test_atm_requests.py +++ b/tests/test_atm_requests.py @@ -11,22 +11,81 @@ def setUp(self): # implicitly get NESSIE_API_KEY from env self.client = Client() - def test_get_atms(self): - lat = 38.9283 - lng = -77.1753 - rad = 1 - observed_atms = self.client.atm.get_atms(lat,lng,rad) - print(observed_atms) - expected_firsttwo_atms = [ - { + # test_get_atms go intos an infinite loop + # def test_get_atms(self): + # lat = 38.9283 + # lng = -77.1753 + # rad = 1 + + # observed_atms = self.client.atm.get_atms(lat,lng,rad) + # print(observed_atms) + # expected_firsttwo_atms = [ + # { + # "_id": "56c66be5a73e492741506f4b", + # "name": "McLean 1", + # "geocode": { + # "lng": -77.17829449999999, + # "lat": 38.932887 + # }, + # "accessibility": 'true', + # "hours": [ + # "24 hours a day, 7 days a week" + # ], + # "address": { + # "state": "VA", + # "zip": "22101", + # "city": "McLean", + # "street_name": "Chain Bridge Road", + # "street_number": "1439" + # }, + # "language_list": [ + # "English" + # ], + # "amount_left": 273775 + # }, + # { + # "_id": "56c66be5a73e492741506f4c", + # "name": "McLean 2", + # "geocode": { + # "lng": -77.17829449999999, + # "lat": 38.932887 + # }, + # "accessibility": 'false', + # "hours": [ + # "24 hours a day, 7 days a week" + # ], + # "address": { + # "state": "VA", + # "zip": "22101", + # "city": "McLean", + # "street_name": "Chain Bridge Road", + # "street_number": "1439" + # }, + # "language_list": [ + # "Portuguese", + # "Korean", + # "Spanish", + # "Chinese", + # "French", + # "English" + # ], + # "amount_left": 444425 + # }] + + # self.assertEqual(observed_atms,expected_atms) + + def test_get_atm(self): + atm = self.client.atm.get_atm('56c66be5a73e492741506f4b') + observed_atm = atm.to_dict() + expected_atm = { "_id": "56c66be5a73e492741506f4b", "name": "McLean 1", "geocode": { "lng": -77.17829449999999, "lat": 38.932887 }, - "accessibility": 'true', + "accessibility": True, "hours": [ "24 hours a day, 7 days a week" ], @@ -41,34 +100,5 @@ def test_get_atms(self): "English" ], "amount_left": 273775 - }, - { - "_id": "56c66be5a73e492741506f4c", - "name": "McLean 2", - "geocode": { - "lng": -77.17829449999999, - "lat": 38.932887 - }, - "accessibility": 'false', - "hours": [ - "24 hours a day, 7 days a week" - ], - "address": { - "state": "VA", - "zip": "22101", - "city": "McLean", - "street_name": "Chain Bridge Road", - "street_number": "1439" - }, - "language_list": [ - "Portuguese", - "Korean", - "Spanish", - "Chinese", - "French", - "English" - ], - "amount_left": 444425 - }] - - self.assertEqual(observed_atms,expected_atms) \ No newline at end of file + } + self.assertEqual(observed_atm, expected_atm) \ No newline at end of file From f2ce195bfc7e258a330d2eb21469c970aa8051b8 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Thu, 1 Feb 2018 08:01:40 +0000 Subject: [PATCH 17/20] add branch_requests test --- tests/test_atm_requests.py | 5 +++ tests/test_branch_requests.py | 62 +++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/test_branch_requests.py diff --git a/tests/test_atm_requests.py b/tests/test_atm_requests.py index e0346e8..5e07219 100644 --- a/tests/test_atm_requests.py +++ b/tests/test_atm_requests.py @@ -10,6 +10,11 @@ class TestAtmRequests(unittest.TestCase): def setUp(self): # implicitly get NESSIE_API_KEY from env self.client = Client() + + # no tearDown needed as its + # read only functions + # def tearDown(self): + # pass # test_get_atms go intos an infinite loop diff --git a/tests/test_branch_requests.py b/tests/test_branch_requests.py new file mode 100644 index 0000000..f0ea565 --- /dev/null +++ b/tests/test_branch_requests.py @@ -0,0 +1,62 @@ +import unittest +import sys, os +path = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0,path+'/../') + +from nessie.client import Client + +class TestBranchRequests(unittest.TestCase): + + def setUp(self): + # implicitly get NESSIE_API_KEY from env + self.client = Client() + + # no tearDown needed as its + # read only functions + # def tearDown(self): + # pass + + def test_get_branch_succeed(self): + branch = self.client.branch.get_branch_by_id('56c66be5a73e4927415071a3') + observed_branch = branch.to_dict() + expected_branch = { + "_id": "56c66be5a73e4927415071a3", + "name": "ARLINGTON", + "phone_number": "(703) 812-8550", + "hours": [ + "Sun", + "Mon 9 AM - 5 PM", + "Tue 9 AM - 5 PM", + "Wed 9 AM - 5 PM", + "Thu 9 AM - 5 PM", + "Fri 9 AM - 6 PM", + "Sat 9 AM - 1 PM" + ], + "notes": [ + "Safe Deposit Box", + "Branch Drive-Up", + "ATM Available", + "Open on Saturday" + ], + "address": { + "street_number": "4700", + "state": "VA", + "street_name": "Lee Highway", + "zip": "22207", + "city": "Arlington" + }, + "geocode": { + "lng": -77.1211338, + "lat": 38.8981779 + } + } + self.assertEqual(observed_branch, expected_branch) + + def test_get_branch_fail(self): + pass + + def test_get_branches_succeed(self): + pass + + def test_get_branches_fail(self): + pass \ No newline at end of file From 55f84dfd88f420da83cf1960024773f1c61ef0c6 Mon Sep 17 00:00:00 2001 From: Wesley Lin Date: Thu, 1 Feb 2018 04:06:43 -0500 Subject: [PATCH 18/20] add readme.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ed1c6f..e74a7b7 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Install python 3.6.2 or greater Setup virtual python environment pip install pipenv - pipenv install + pipenv install --dev To add packages From e2be4f8bea35e55ac6bcc1eb64c745a0ec7806d1 Mon Sep 17 00:00:00 2001 From: Wesley Lin Date: Thu, 1 Feb 2018 04:22:46 -0500 Subject: [PATCH 19/20] add transfer scaffodling --- docs/overview.md | 1 + nessie/models/bill.py | 2 -- nessie/models/transfer.py | 26 ++++++++++++++++++++++++++ nessie/transactionRequests.py | 3 ++- nessie/transferRequests.py | 6 ++++++ 5 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 nessie/models/transfer.py create mode 100644 nessie/transferRequests.py diff --git a/docs/overview.md b/docs/overview.md index 5fbc1d2..816264b 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -16,6 +16,7 @@ Customer 1 -- * Accounts ## Transactions +#### Bill #### Desposit #### Loan #### Purchase diff --git a/nessie/models/bill.py b/nessie/models/bill.py index 6270bc5..0988a87 100644 --- a/nessie/models/bill.py +++ b/nessie/models/bill.py @@ -1,8 +1,6 @@ class Bill(): def __init__(self, _json): - print(_json) - self.bill_id = _json['_id'] self.status = _json["status"] self.payee = _json["payee"] diff --git a/nessie/models/transfer.py b/nessie/models/transfer.py new file mode 100644 index 0000000..2e4bf69 --- /dev/null +++ b/nessie/models/transfer.py @@ -0,0 +1,26 @@ + +class Transfer(): + def __init__(self, _json): + self.transfer_id = _json['_id'] + self.type = _json['type'] + self.transaction_date = _json['transaction_date'] + self.status = ['status'] + self.medium = _json['medium'] + self.payer_id = _json['payer_id'] + self.payee_id = _json['payee_id'] + self.description = _json['description'] + + def to_dict(self): + return vars(self) + + +# """ +# "_id": "string", +# "type": "p2p", +# "transaction_date": "2018-02-01", +# "status": "pending", +# "medium": "balance", +# "payer_id": "string", +# "payee_id": "string", +# "description": "string" +# """ \ No newline at end of file diff --git a/nessie/transactionRequests.py b/nessie/transactionRequests.py index c0aa641..ea67813 100644 --- a/nessie/transactionRequests.py +++ b/nessie/transactionRequests.py @@ -1,6 +1,7 @@ # base class transaction # should not be directly used import requests +from abc import ABC from nessie import utils """ @@ -22,7 +23,7 @@ DELETE delete selected transaction """ -class transactionRequest(): +class TransactionRequest(ABC): def __init__(self, api_key, transaction_name:str, transaction_class): self.key = api_key self.base_url = utils.constants.baseUrl diff --git a/nessie/transferRequests.py b/nessie/transferRequests.py new file mode 100644 index 0000000..cf4497f --- /dev/null +++ b/nessie/transferRequests.py @@ -0,0 +1,6 @@ +from .transactionRequests import TransactionRequest +from .models.transfer import Transfer + +class TransferRequests(TransactionRequest): + def __init__(self, api_key): + super().__init__(api_key, 'transfer',Transfer) \ No newline at end of file From 473d941a12f352de215d2ff470f752fa2ea3f2a6 Mon Sep 17 00:00:00 2001 From: Wesley LIn Date: Tue, 13 Feb 2018 20:14:00 +0000 Subject: [PATCH 20/20] adding transfer stuff --- nessie/transferRequest.py | 34 +++++++++++++++++ nessie/transferRequests.py | 6 --- tests/test_transfer_requests.py | 67 +++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 nessie/transferRequest.py delete mode 100644 nessie/transferRequests.py create mode 100644 tests/test_transfer_requests.py diff --git a/nessie/transferRequest.py b/nessie/transferRequest.py new file mode 100644 index 0000000..05634b7 --- /dev/null +++ b/nessie/transferRequest.py @@ -0,0 +1,34 @@ +import requests + +from .transactionRequests import TransactionRequest +from .models.transfer import Transfer +from .utils.constants import baseUrl + +class TransferRequests(): + def __init__(self, api_key): + self.key = key + + # a GET request for transfer with + # corresponding transfer_id + def get_transfer(self, transfer_id): + url = f'{baseUrl}/transfers/{transfer_id}?key={self.key}' + response = requests.get(url) + if (response.status_code != 200): + raise NessieApiError(response) + + # GET request to fetch all transfer transactions + # from the specified account + def get_transfers_of_account(self, account_id): + url = f'{baseUrl}/accounts/{account_id}/transfers?key={self.key}' + + def create_transfer(self,medium,payee_id,transaction_date, status,description): + url = f'{baseUrl}/accounts/{account_id}/transfers?key={self.key}' + + body = { + 'medium': medium, + 'payee_id': payee_id, + 'transaction_date': transaction_date, + 'status': status, + 'description':description + } + response = requests.post(url, json=body) \ No newline at end of file diff --git a/nessie/transferRequests.py b/nessie/transferRequests.py deleted file mode 100644 index cf4497f..0000000 --- a/nessie/transferRequests.py +++ /dev/null @@ -1,6 +0,0 @@ -from .transactionRequests import TransactionRequest -from .models.transfer import Transfer - -class TransferRequests(TransactionRequest): - def __init__(self, api_key): - super().__init__(api_key, 'transfer',Transfer) \ No newline at end of file diff --git a/tests/test_transfer_requests.py b/tests/test_transfer_requests.py new file mode 100644 index 0000000..b1ddb8b --- /dev/null +++ b/tests/test_transfer_requests.py @@ -0,0 +1,67 @@ +import unittest +import sys, os +path = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0,path+'/../') + +from nessie.accountRequests import AccountRequests +from nessie.billRequests import BillRequest +from nessie.dataRequests import DataRequests +from nessie.client import Client +from nessie.utils.exceptions import NessieApiError + + +# def test_create_bill(self): +# bill_factory = billRequests.BillRequest("wkey") + + + +class TestBillRequests(): + # create some dummy bills + def setUp(self): + # implicitly get NESSIE_API_KEY from env + self.client = Client() + + bill_factory = self.client.bill + bill = bill_factory.create_bill(account_id, + status='pending', + payee='bobby', + nickname='bob', + payment_date='2018-01-10', + recurring_date=1, + payment_amount=10 + ) + + def tearDown(self): + data_deletor = self.client.data + response = data_deletor.delete_data('Bills') + d = DataRequests('7e9b72fdb7b286fcd0aae87deb0e09a2') + d.delete_data('Bills') + + + + def test_get_bill_succeed(self): + print("test_get_bill_succeed") + bill_factory = self.client.bill + result = bill_factory.get_account_bills(account_id) + print(result) + # result = bill_factory.get_bill("5a261c3883a71c405074fcbd") + # expected_result = {'bill_id': '5a261c3883a71c405074fcbd', 'status': 'pending', 'payee': 'string', 'nickname': 'string', 'payment_date': '2017-12-05', 'recurring_date': 1, 'payment_amount': 23, 'creation_date': '2017-12-05', 'account_id': '5a261a0483a71c405074fcbc'} + self.assertEqual(result[0]['payment_date'], '2018-01-10') + data_deletor = DataRequests(wkey) + + # try fetching a bill that doesn't exist + def test_get_nonreal_bill_fail(self): + print("test_get_nonreal_bill_fail") + bill_factory = self.client.bill + + expected_status_code = 404 + # expected_message = 'Invalid ID' + result = {} + try: + try_result = bill_factory.get_bill("fake") + except NessieApiError as e: + result = e + + self.assertEqual(result.code,expected_status_code) + + \ No newline at end of file