Skip to content

Commit

Permalink
Merge pull request openprocurement#7 from selurvedu/fix-#6
Browse files Browse the repository at this point in the history
Fix PR openprocurement#6; clean up and reformat code
  • Loading branch information
myroslav committed Nov 12, 2015
2 parents 05a4067 + 26e75c3 commit dd6b014
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 70 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
openprocurement.client.python
=============================

Reference implementation of a client for OpenProcurement API.

This product may contain traces of nuts.
6 changes: 0 additions & 6 deletions README.txt

This file was deleted.

145 changes: 88 additions & 57 deletions openprocurement_client/client.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
# from gevent import monkey
# monkey.patch_all()
from StringIO import StringIO
from functools import wraps
from iso8601 import parse_date
from munch import munchify
from restkit import BasicAuth, Resource, request, errors
from restkit import BasicAuth, errors, request, Resource
from retrying import retry
from simplejson import dumps, loads
from tempfile import NamedTemporaryFile
from StringIO import StringIO
from urlparse import parse_qs, urlparse
import sys

IGNORE_PARAMS = ('uri', 'path',)
IGNORE_PARAMS = ('uri', 'path')


def verify_file(fn):
@wraps(fn)
Expand All @@ -27,10 +24,15 @@ def wrapper(self, file_, *args, **kwargs):
'file-like object, got {}'.format(type(file_)))
return wrapper


class InvalidResponse(Exception):
pass


class NoToken(Exception):
pass


class Client(Resource):
"""docstring for API"""
def __init__(self, key,
Expand All @@ -44,10 +46,10 @@ def __init__(self, key,
self.params = {"mode": "_all_"}
self.headers = {"Content-Type": "application/json"}

def request(self, method, path=None, payload=None, headers={},
def request(self, method, path=None, payload=None, headers=None,
params_dict=None, **params):
_headers = dict(self.headers)
_headers.update(headers)
_headers.update(headers or {})
try:
response = super(Client, self).request(
method, path=path, payload=payload, headers=_headers,
Expand All @@ -61,7 +63,6 @@ def request(self, method, path=None, payload=None, headers={},
self.headers['Cookie'] = e.response.headers['Set-Cookie']
raise e


def patch(self, path=None, payload=None, headers=None,
params_dict=None, **params):
""" HTTP PATCH
Expand All @@ -76,29 +77,26 @@ def patch(self, path=None, payload=None, headers=None,
return self.request("PATCH", path=path, payload=payload,
headers=headers, params_dict=params_dict, **params)

def delete(self, path=None, headers=None,
):
def delete(self, path=None, headers=None):
""" HTTP DELETE
- path: string additionnal path to the uri
- headers: dict, optionnal headers that will
be added to HTTP request.
- params: Optionnal parameterss added to the request
"""
return self.request("DELETE", path=path, headers=headers,
)
return self.request("DELETE", path=path, headers=headers)

def _update_params(self, params):
for key in params:
if key not in IGNORE_PARAMS:
self.params[key] = params[key]

############################################################################
###########################################################################
# GET ITEMS LIST API METHODS
############################################################################
###########################################################################

@retry(stop_max_attempt_number=5)
def get_tenders(self, params={}, feed='changes'):
#import pdb; pdb.Pdb(stdout=sys.__stdout__).set_trace()
params['feed'] = feed
try:
self._update_params(params)
Expand All @@ -110,19 +108,22 @@ def get_tenders(self, params={}, feed='changes'):
self._update_params(tender_list.next_page)
return tender_list.data

except errors.ResourceNotFound as e:
except errors.ResourceNotFound:
del self.params['offset']
raise

raise InvalidResponse

def get_latest_tenders(self, date, tenderID):
iso_dt=parse_date(date)
def get_latest_tenders(self, date, tender_id):
iso_dt = parse_date(date)
dt = iso_dt.strftime("%Y-%m-%d")
tm = iso_dt.strftime("%H:%M:%S")
response = self._get_resource_item(
self.prefix_path + '?offset={}T{}&opt_fields=tenderID&mode=test'.format(dt, tm),

'{}?offset={}T{}&opt_fields=tender_id&mode=test'.format(
self.prefix_path,
dt,
tm
)
)
if response.status_int == 200:
tender_list = munchify(loads(response.body_string()))
Expand All @@ -132,8 +133,9 @@ def get_latest_tenders(self, date, tenderID):

def _get_tender_resource_list(self, tender, items_name):
return self._get_resource_item(
self.prefix_path + '/{}/{}'.format(tender.data.id, items_name),
headers={'X-Access-Token': getattr(getattr(tender, 'access', ''), 'token', '')}
'{}/{}/{}'.format(self.prefix_path, tender.data.id, items_name),
headers={'X-Access-Token':
getattr(getattr(tender, 'access', ''), 'token', '')}
)

def get_questions(self, tender, params={}):
Expand All @@ -145,9 +147,9 @@ def get_documents(self, tender, params={}):
def get_awards(self, tender, params={}):
return self._get_tender_resource_list(tender, "awards")

############################################################################
###########################################################################
# CREATE ITEM API METHODS
############################################################################
###########################################################################
def _create_resource_item(self, url, payload, headers={}):
headers.update(self.headers)
response_item = self.post(
Expand All @@ -159,9 +161,10 @@ def _create_resource_item(self, url, payload, headers={}):

def _create_tender_resource_item(self, tender, item_obj, items_name):
return self._create_resource_item(
self.prefix_path + '/{}/'.format(tender.data.id) + items_name,
'{}/{}/{}'.format(self.prefix_path, tender.data.id, items_name),
item_obj,
headers={'X-Access-Token': getattr(getattr(tender, 'access', ''), 'token', '')}
headers={'X-Access-Token':
getattr(getattr(tender, 'access', ''), 'token', '')}
)

def create_tender(self, tender):
Expand All @@ -173,9 +176,9 @@ def create_question(self, tender, question):
def create_bid(self, tender, bid):
return self._create_tender_resource_item(tender, bid, "bids")

############################################################################
###########################################################################
# GET ITEM API METHODS
############################################################################
###########################################################################

def _get_resource_item(self, url, headers={}):
headers.update(self.headers)
Expand All @@ -185,24 +188,29 @@ def _get_resource_item(self, url, headers={}):
raise InvalidResponse

def get_tender(self, id):
return self._get_resource_item(self.prefix_path + '/{}'.format(id))
return self._get_resource_item('{}/{}'.format(self.prefix_path, id))

def _get_tender_resource_item(self, tender, item_id, items_name,
access_token=""):
if access_token:
headers = {'X-Access-Token': access_token}
else:
headers = {'X-Access-Token': getattr(getattr(tender, 'access', ''), 'token', '')}
headers = {'X-Access-Token':
getattr(getattr(tender, 'access', ''), 'token', '')}
return self._get_resource_item(
self.prefix_path + '/{}/{}/{}'.format(tender.data.id, items_name, item_id),
'{}/{}/{}/{}'.format(self.prefix_path,
tender.data.id,
items_name,
item_id),
headers=headers
)

def get_question(self, tender, question_id):
return self._get_tender_resource_item(tender, question_id, "questions")

def get_bid(self, tender, bid_id, access_token):
return self._get_tender_resource_item(tender, bid_id, "bids", access_token)
return self._get_tender_resource_item(tender, bid_id, "bids",
access_token)

def get_file(self, tender, url, access_token):
parsed_url = urlparse(url)
Expand All @@ -219,12 +227,14 @@ def get_file(self, tender, url, access_token):
if response_item.status_int == 302:
response_obj = request(response_item.headers['location'])
if response_obj.status_int == 200:
return response_obj.body_string(), response_obj.headers['Content-Disposition'].split(";")[1].split('"')[1]
return response_obj.body_string(), \
response_obj.headers['Content-Disposition'] \
.split(";")[1].split('"')[1]
raise InvalidResponse

############################################################################
###########################################################################
# PATCH ITEM API METHODS
############################################################################
###########################################################################

def _patch_resource_item(self, url, payload, headers={}):
headers.update(self.headers)
Expand All @@ -237,28 +247,33 @@ def _patch_resource_item(self, url, payload, headers={}):

def _patch_tender_resource_item(self, tender, item_obj, items_name):
return self._patch_resource_item(
self.prefix_path + '/{}/{}/{}'.format(
tender.data.id, items_name, item_obj.data.id
), item_obj, headers={'X-Access-Token': getattr(getattr(tender, 'access', ''), 'token', '')}
'{}/{}/{}/{}'.format(
self.prefix_path, tender.data.id, items_name, item_obj.data.id
),
item_obj,
headers={'X-Access-Token':
getattr(getattr(tender, 'access', ''), 'token', '')}
)

def patch_tender(self, tender):
return self._patch_resource_item(
self.prefix_path + '/{}'.format(tender["data"]["id"]), tender,
headers={'X-Access-Token': getattr(getattr(tender, 'access', ''), 'token', '')}
'{}/{}'.format(self.prefix_path, tender["data"]["id"]), tender,
headers={'X-Access-Token':
getattr(getattr(tender, 'access', ''), 'token', '')}
)

def patch_question(self, tender, question):
return self._patch_tender_resource_item(tender, question, "questions")

def patch_bid(self, tender, bid):
return self._patch_tender_resource_item(tender, bid, "bids")

def patch_award(self, tender, award):
return self._patch_tender_resource_item(tender, award, "awards")

############################################################################
###########################################################################
# UPLOAD FILE API METHODS
############################################################################
###########################################################################
def _upload_resource_file(self, url, data, headers={}, method='post'):
file_headers = {}
file_headers.update(self.headers)
Expand All @@ -274,9 +289,10 @@ def _upload_resource_file(self, url, data, headers={}, method='post'):
@verify_file
def upload_document(self, file_, tender):
return self._upload_resource_file(
self.prefix_path + '/{}/documents'.format(tender.data.id),
'{}/{}/documents'.format(self.prefix_path, tender.data.id),
{"file": file_},
headers={'X-Access-Token': getattr(getattr(tender, 'access', ''), 'token', '')}
headers={'X-Access-Token':
getattr(getattr(tender, 'access', ''), 'token', '')}
)

def upload_tender_document(self, filename, tender):
Expand All @@ -289,9 +305,14 @@ def upload_tender_document(self, filename, tender):
@verify_file
def upload_bid_document(self, file_, tender, bid_id):
return self._upload_resource_file(
self.prefix_path + '/{}/'.format(tender.data.id)+"bids/"+bid_id+'/documents',
'{}/{}/bids/{}/documents'.format(
self.prefix_path,
tender.data.id,
bid_id
),
{"file": file_},
headers={'X-Access-Token': getattr(getattr(tender, 'access', ''), 'token', '')}
headers={'X-Access-Token':
getattr(getattr(tender, 'access', ''), 'token', '')}
)

def update_bid_document(self, filename, tender, bid_id, document_id):
Expand All @@ -300,27 +321,37 @@ def update_bid_document(self, filename, tender, bid_id, document_id):
file_.write("fixed text data")
file_.seek(0)
return self._upload_resource_file(
self.prefix_path + '/{}/'.format(tender.data.id)+"bids/"+bid_id+'/documents/'+document_id,
'{}/{}/bids/{}/documents/{}'.format(
self.prefix_path,
tender.data.id,
bid_id,
document_id
),
{"file": file_},
headers={'X-Access-Token': getattr(getattr(tender, 'access', ''), 'token', '')},
headers={'X-Access-Token':
getattr(getattr(tender, 'access', ''), 'token', '')},
method='put'
)

############################################################################
###########################################################################
# DELETE ITEMS LIST API METHODS
############################################################################
###########################################################################

def _delete_resource_item(self, url, headers={}):

response_item = self.delete(
url, headers=headers)
response_item = self.delete(url, headers=headers)
if response_item.status_int == 200:
return munchify(loads(response_item.body_string()))
raise InvalidResponse

def delete_bid(self, tender, bid):
return self._delete_resource_item(
self.prefix_path + '/{}/'.format(tender.data.id)+"bids/"+bid.data.id,
headers={'X-Access-Token': getattr(getattr(bid, 'access', ''), 'token', '')}
'{}/{}/bids/{}'.format(
self.prefix_path,
tender.data.id,
bid.data.id
),
headers={'X-Access-Token':
getattr(getattr(bid, 'access', ''), 'token', '')}
)
############################################################################
###########################################################################
2 changes: 1 addition & 1 deletion openprocurement_client/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from openprocurement_client.client import Client
import logging
from time import sleep
import logging
logger = logging.getLogger()


Expand Down
14 changes: 8 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
from setuptools import setup, find_packages
from setuptools import find_packages, setup
import os

version = '1.0.a1'
version = '1.0a2'

setup(name='openprocurement_client',
version=version,
description="",
long_description=open("README.txt").read() + "\n" +
open(os.path.join("docs", "HISTORY.txt")).read(),
long_description="{0}\n{1}".format(
open("README.txt").read(),
open(os.path.join("docs", "HISTORY.txt")).read()
),
# Get more strings from
# http://pypi.python.org/pypi?:action=list_classifiers
classifiers=[
"Programming Language :: Python",
],
"Programming Language :: Python",
],
keywords='',
author='',
author_email='',
Expand Down

0 comments on commit dd6b014

Please sign in to comment.