Skip to content

Support Python3, update features, fix indent, update setup.py #43

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

Open
wants to merge 4 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
315 changes: 224 additions & 91 deletions README.md

Large diffs are not rendered by default.

40 changes: 25 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@


import sys
from setuptools import setup, find_packages

install_requires = [
'future'
]

if (sys.version_info < (3,0)):
# has a different name if supporting Python3
install_requires.append('python-ntlm')
else:
install_requires.append('python-ntlm3')

setup(
name = "v1pysdk",
version = "0.4",
description = "VersionOne API client",
version = "0.5",
description = "VersionOne API client",
author = "Joe Koberg (VersionOne, Inc.)",
author_email = "[email protected]",
license = "MIT/BSD",
keywords = "versionone v1 api sdk",
url = "http://github.com/VersionOne/v1pysdk",
url = "http://github.com/mtalexan/VersionOne.SDK.Python.git",

packages = [
'v1pysdk',
],

install_requires = [
'elementtree',
'testtools',
'iso8601',
'python-ntlm',
],

test_suite = "v1pysdk.tests",


install_requires = install_requires,

#tests don't work, so ignore them
#tests_require = [
# 'testtools'
#],
#
#test_suite = "v1pysdk.tests",

)


Expand Down
4 changes: 2 additions & 2 deletions v1pysdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"""


from v1meta import V1Meta
from v1poll import V1Poll
from .v1meta import V1Meta
from .v1poll import V1Poll

40 changes: 22 additions & 18 deletions v1pysdk/base_asset.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
from future.utils import with_metaclass

from pprint import pformat as pf

from query import V1Query
from .query import V1Query

class BaseAsset(object):
class IterableType(type):
"The type that's instantiated to make BaseAsset class must have an __iter__, "
"so we provide a metaclass (a thing that provides a class when instantiated) "
"that knows how to be iterated over, so we can say list(v1.Story)"

def __iter__(Class):
for instance in Class.query():
instance.needs_refresh = True
yield instance

# Required dummy for with_metaclass to work properly
class DummyBaseAsset(object):
pass

class BaseAsset(with_metaclass(IterableType,DummyBaseAsset)):
"""Provides common methods for the dynamically derived asset type classes
built by V1Meta.asset_class"""

@classmethod
def query(Class, where=None, sel=None):
'Takes a V1 Data query string and returns an iterable of all matching items'
Expand Down Expand Up @@ -43,22 +58,11 @@ def create(Class, **newdata):
"create new asset on server and return created asset proxy instance"
return Class._v1_v1meta.create_asset(Class._v1_asset_type_name, newdata)

class IterableType(type):
def __iter__(Class):
for instance in Class.query():
instance.needs_refresh = True
yield instance

"The type that's instantiated to make THIS class must have an __iter__, "
"so we provide a metaclass (a thing that provides a class when instantiated) "
"that knows how to be iterated over, so we can say list(v1.Story)"
__metaclass__ = IterableType

def __new__(Class, oid, moment=None):
"Tries to get an instance out of the cache first, otherwise creates one"
cache_key = (Class._v1_asset_type_name, oid, moment)
cache = Class._v1_v1meta.global_cache
if cache.has_key(cache_key):
if cache_key in cache:
self = cache[cache_key]
else:
self = object.__new__(Class)
Expand Down Expand Up @@ -116,7 +120,7 @@ def repr_shallow(self, d):
return pf( dict(
(k, self.repr_dummy(v))
for (k,v)
in d.items()
in d.items()
if v
)
)
Expand All @@ -134,12 +138,12 @@ def __repr__(self):
def _v1_getattr(self, attr):
"Intercept access to missing attribute names. "
"first return uncommitted data, then refresh if needed, then get single attr, else fail"
if self._v1_new_data.has_key(attr):
if attr in self._v1_new_data:
value = self._v1_new_data[attr]
else:
if self._v1_needs_refresh:
self._v1_refresh()
if attr not in self._v1_current_data.keys():
if attr not in list(self._v1_current_data.keys()):
self._v1_current_data[attr] = self._v1_get_single_attr(attr)
value = self._v1_current_data[attr]
return value
Expand Down
2 changes: 1 addition & 1 deletion v1pysdk/cache_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def decorator(old_f):
data = {}
def new_f(self, *args, **kw):
new_key = keyfunc(old_f, args, kw, data)
if data.has_key(new_key):
if new_key in data:
return data[new_key]
new_value = old_f(self, *args, **kw)
data[new_key] = new_value
Expand Down
31 changes: 23 additions & 8 deletions v1pysdk/client.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@

import logging, time, base64
import urllib2
from urllib2 import Request, urlopen, HTTPError, HTTPBasicAuthHandler, HTTPCookieProcessor
from urllib import urlencode
from urlparse import urlunparse, urlparse

import sys
if (sys.version_info < (3,0)):
#Python2 way of doing this
import urllib2 as theUrlLib #must be a name matching the Python3 urllib.request
from urllib2 import Request, urlopen, HTTPBasicAuthHandler, HTTPCookieProcessor
from urllib import urlencode
from urlparse import urlunparse,urlparse
else:
#Python3 way of doing this
import urllib.request as theUrlLib #must be a name matching the Python2 urllib2
import urllib.error, urllib.parse
from urllib.request import Request, urlopen, HTTPBasicAuthHandler, HTTPCookieProcessor
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.parse import urlunparse, urlparse

try:
from xml.etree import ElementTree
Expand All @@ -15,7 +27,10 @@
AUTH_HANDLERS = [HTTPBasicAuthHandler]

try:
from ntlm.HTTPNtlmAuthHandler import HTTPNtlmAuthHandler
if (sys.version_info < (3,0)):
from ntlm.HTTPNtlmAuthHandler import HTTPNtlmAuthHandler
else:
from ntlm3.HTTPNtlmAuthHandler import HTTPNtlmAuthHandler
except ImportError:
logging.warn("Windows integrated authentication module (ntlm) not found.")
else:
Expand Down Expand Up @@ -70,10 +85,10 @@ def __init__(self, address="localhost", instance="VersionOne.Web", username='',

def _install_opener(self):
base_url = self.build_url('')
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager = theUrlLib.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, base_url, self.username, self.password)
handlers = [HandlerClass(password_manager) for HandlerClass in AUTH_HANDLERS]
self.opener = urllib2.build_opener(*handlers)
self.opener = theUrlLib.build_opener(*handlers)
self.opener.add_handler(HTTPCookieProcessor())

def http_get(self, url):
Expand Down Expand Up @@ -129,7 +144,7 @@ def fetch(self, path, query='', postdata=None):
self._debug_headers(response.headers)
self._debug_body(body, response.headers)
return (None, body)
except HTTPError, e:
except HTTPError as e:
if e.code == 401:
raise
body = e.fp.read()
Expand Down
Loading