Skip to content
Browse files

- Improve response for failed requests - added additional HTTP error …

…codes, don't try and JSON decode errors.

- Documentation improvements


Signed-off-by: Mike MacCana <mike.maccana@gmail.com>
  • Loading branch information...
1 parent 5b76488 commit 95c5a2c9f16e417e37a2bf5081c9425734fb6b7b @mikemaccana committed Oct 20, 2010
Showing with 303 additions and 37 deletions.
  1. +207 −0 .gitignore
  2. +44 −5 README.markdown
  3. +52 −32 dnsimple.py
View
207 .gitignore
@@ -0,0 +1,207 @@
+bin/activate
+bin/activate_this.py
+bin/activate_this.pyc
+bin/easy_install
+bin/easy_install-2.6
+bin/get_env_details
+bin/pip
+bin/postactivate
+bin/postdeactivate
+bin/preactivate
+bin/predeactivate
+bin/python
+bin/python2.6
+dnsimple.pyc
+include/python2.6
+ipyhelper.py
+ipyhelper.pyc
+lib/python2.6/UserDict.py
+lib/python2.6/UserDict.pyc
+lib/python2.6/UserDict.pyo
+lib/python2.6/_abcoll.py
+lib/python2.6/_abcoll.pyc
+lib/python2.6/_abcoll.pyo
+lib/python2.6/abc.py
+lib/python2.6/abc.pyc
+lib/python2.6/abc.pyo
+lib/python2.6/codecs.py
+lib/python2.6/codecs.pyc
+lib/python2.6/codecs.pyo
+lib/python2.6/config
+lib/python2.6/copy_reg.py
+lib/python2.6/copy_reg.pyc
+lib/python2.6/copy_reg.pyo
+lib/python2.6/distutils/__init__.py
+lib/python2.6/distutils/__init__.pyc
+lib/python2.6/distutils/distutils.cfg
+lib/python2.6/encodings
+lib/python2.6/fnmatch.py
+lib/python2.6/fnmatch.pyc
+lib/python2.6/fnmatch.pyo
+lib/python2.6/genericpath.py
+lib/python2.6/genericpath.pyc
+lib/python2.6/genericpath.pyo
+lib/python2.6/lib-dynload
+lib/python2.6/linecache.py
+lib/python2.6/linecache.pyc
+lib/python2.6/linecache.pyo
+lib/python2.6/locale.py
+lib/python2.6/locale.pyc
+lib/python2.6/locale.pyo
+lib/python2.6/ntpath.py
+lib/python2.6/ntpath.pyc
+lib/python2.6/ntpath.pyo
+lib/python2.6/orig-prefix.txt
+lib/python2.6/os.py
+lib/python2.6/os.pyc
+lib/python2.6/os.pyo
+lib/python2.6/posixpath.py
+lib/python2.6/posixpath.pyc
+lib/python2.6/posixpath.pyo
+lib/python2.6/re.py
+lib/python2.6/re.pyc
+lib/python2.6/re.pyo
+lib/python2.6/site-packages/easy-install.pth
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/PKG-INFO
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/SOURCES.txt
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/dependency_links.txt
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/entry_points.txt
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/not-zip-safe
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/EGG-INFO/top_level.txt
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/__init__.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/__init__.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/backwardcompat.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/backwardcompat.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/basecommand.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/basecommand.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/baseparser.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/baseparser.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/__init__.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/__init__.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/bundle.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/bundle.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/completion.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/completion.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/freeze.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/freeze.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/help.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/help.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/install.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/install.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/search.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/search.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/uninstall.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/uninstall.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/unzip.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/unzip.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/zip.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/commands/zip.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/exceptions.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/exceptions.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/index.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/index.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/locations.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/locations.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/log.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/log.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/req.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/req.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/runner.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/runner.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/util.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/util.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/__init__.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/__init__.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/bazaar.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/bazaar.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/git.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/git.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/mercurial.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/mercurial.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/subversion.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/vcs/subversion.pyc
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/venv.py
+lib/python2.6/site-packages/pip-0.7.2-py2.6.egg/pip/venv.pyc
+lib/python2.6/site-packages/setuptools-0.6c11-py2.6.egg
+lib/python2.6/site-packages/setuptools.pth
+lib/python2.6/site-packages/simplejson-2.1.1-py2.6.egg-info/PKG-INFO
+lib/python2.6/site-packages/simplejson-2.1.1-py2.6.egg-info/SOURCES.txt
+lib/python2.6/site-packages/simplejson-2.1.1-py2.6.egg-info/dependency_links.txt
+lib/python2.6/site-packages/simplejson-2.1.1-py2.6.egg-info/installed-files.txt
+lib/python2.6/site-packages/simplejson-2.1.1-py2.6.egg-info/top_level.txt
+lib/python2.6/site-packages/simplejson-2.1.1-py2.6.egg-info/zip-safe
+lib/python2.6/site-packages/simplejson/__init__.py
+lib/python2.6/site-packages/simplejson/__init__.pyc
+lib/python2.6/site-packages/simplejson/_speedups.so
+lib/python2.6/site-packages/simplejson/decoder.py
+lib/python2.6/site-packages/simplejson/decoder.pyc
+lib/python2.6/site-packages/simplejson/encoder.py
+lib/python2.6/site-packages/simplejson/encoder.pyc
+lib/python2.6/site-packages/simplejson/ordered_dict.py
+lib/python2.6/site-packages/simplejson/ordered_dict.pyc
+lib/python2.6/site-packages/simplejson/scanner.py
+lib/python2.6/site-packages/simplejson/scanner.pyc
+lib/python2.6/site-packages/simplejson/tests/__init__.py
+lib/python2.6/site-packages/simplejson/tests/__init__.pyc
+lib/python2.6/site-packages/simplejson/tests/test_check_circular.py
+lib/python2.6/site-packages/simplejson/tests/test_check_circular.pyc
+lib/python2.6/site-packages/simplejson/tests/test_decimal.py
+lib/python2.6/site-packages/simplejson/tests/test_decimal.pyc
+lib/python2.6/site-packages/simplejson/tests/test_decode.py
+lib/python2.6/site-packages/simplejson/tests/test_decode.pyc
+lib/python2.6/site-packages/simplejson/tests/test_default.py
+lib/python2.6/site-packages/simplejson/tests/test_default.pyc
+lib/python2.6/site-packages/simplejson/tests/test_dump.py
+lib/python2.6/site-packages/simplejson/tests/test_dump.pyc
+lib/python2.6/site-packages/simplejson/tests/test_encode_basestring_ascii.py
+lib/python2.6/site-packages/simplejson/tests/test_encode_basestring_ascii.pyc
+lib/python2.6/site-packages/simplejson/tests/test_encode_for_html.py
+lib/python2.6/site-packages/simplejson/tests/test_encode_for_html.pyc
+lib/python2.6/site-packages/simplejson/tests/test_fail.py
+lib/python2.6/site-packages/simplejson/tests/test_fail.pyc
+lib/python2.6/site-packages/simplejson/tests/test_float.py
+lib/python2.6/site-packages/simplejson/tests/test_float.pyc
+lib/python2.6/site-packages/simplejson/tests/test_indent.py
+lib/python2.6/site-packages/simplejson/tests/test_indent.pyc
+lib/python2.6/site-packages/simplejson/tests/test_pass1.py
+lib/python2.6/site-packages/simplejson/tests/test_pass1.pyc
+lib/python2.6/site-packages/simplejson/tests/test_pass2.py
+lib/python2.6/site-packages/simplejson/tests/test_pass2.pyc
+lib/python2.6/site-packages/simplejson/tests/test_pass3.py
+lib/python2.6/site-packages/simplejson/tests/test_pass3.pyc
+lib/python2.6/site-packages/simplejson/tests/test_recursion.py
+lib/python2.6/site-packages/simplejson/tests/test_recursion.pyc
+lib/python2.6/site-packages/simplejson/tests/test_scanstring.py
+lib/python2.6/site-packages/simplejson/tests/test_scanstring.pyc
+lib/python2.6/site-packages/simplejson/tests/test_separators.py
+lib/python2.6/site-packages/simplejson/tests/test_separators.pyc
+lib/python2.6/site-packages/simplejson/tests/test_speedups.py
+lib/python2.6/site-packages/simplejson/tests/test_speedups.pyc
+lib/python2.6/site-packages/simplejson/tests/test_unicode.py
+lib/python2.6/site-packages/simplejson/tests/test_unicode.pyc
+lib/python2.6/site-packages/simplejson/tool.py
+lib/python2.6/site-packages/simplejson/tool.pyc
+lib/python2.6/site.py
+lib/python2.6/site.pyc
+lib/python2.6/sre.py
+lib/python2.6/sre.pyc
+lib/python2.6/sre.pyo
+lib/python2.6/sre_compile.py
+lib/python2.6/sre_compile.pyc
+lib/python2.6/sre_compile.pyo
+lib/python2.6/sre_constants.py
+lib/python2.6/sre_constants.pyc
+lib/python2.6/sre_constants.pyo
+lib/python2.6/sre_parse.py
+lib/python2.6/sre_parse.pyc
+lib/python2.6/sre_parse.pyo
+lib/python2.6/stat.py
+lib/python2.6/stat.pyc
+lib/python2.6/stat.pyo
+lib/python2.6/types.py
+lib/python2.6/types.pyc
+lib/python2.6/types.pyo
+lib/python2.6/warnings.py
+lib/python2.6/warnings.pyc
+lib/python2.6/warnings.pyo
+.dnsimple
View
49 README.markdown
@@ -3,10 +3,12 @@ Python DNSimple
## Introduction
-This is a client for the DNSimple REST API. It allows you to fetch existing domain info, and register new domains. More features are on the way in future.
+This is a client for the DNSimple REST API. It currently allows you to fetch existing domain info, as well as bulk-register new domains. More features are on the way.
### Getting started
+You'll need the simplejson module installed.
+
Create a file called .dnsimple in the current dir with the following data:
username: email@domain.com
@@ -15,21 +17,58 @@ Create a file called .dnsimple in the current dir with the following data:
Then import the module:
from dnsimple import DNSimple
- dns = DNSimple(username,password)
+
+And create a DNSimple object:
+
+ dns = DNSimple()
### Check out your existing domains:
Just run:
domains = dns.getdomains()
- for domain in domains:
- print domain['domain']['name']
+
+Results appear as a Python dict:
+
+ {'domain': {'created_at': '2010-10-14T09:45:32Z',
+ 'expires_at': '10/14/2011 5:45:00 AM',
+ 'id': 999,
+ 'last_enom_order_id': None,
+ 'name': 'yourdomain.com',
+ 'name_server_status': 'active',
+ 'registrant_id': 99,
+ 'registration_status': 'registered',
+ 'updated_at': '2010-10-14T10:00:14Z',
+ 'user_id': 99}},
+ {'domain': {'created_at': '2010-10-15T16:02:34Z',
+ 'expires_at': '10/15/2011 12:02:00 PM',
+ 'id': 999,
+ 'last_enom_order_id': None,
+ 'name': 'anotherdomain.com',
+ 'name_server_status': 'active',
+ 'registrant_id': 99,
+ 'registration_status': 'registered',
+ 'updated_at': '2010-10-15T16:30:16Z',
+ 'user_id': 99}}]
+
+
+### Check out a specific domain
+
+ dns.getdomain('mikemaccana.com')
+
+Results are the same as getdomains() above, but only show the domain specified.
### Register a new domain
Just run:
- test = dnsimple.register('yourdomain.com','16')
+ dns.register('newdomain.com')
+
+This will register 'newdomain.com', automatically picking the registrant\_id from your first domain. To specify a particularly registrant\_id, just run:
+
+ dns.register('newdomain.com',99)
+
+Responses will be in a dictionary describing the newly created domain, same as the getdomain() above.
### License
View
84 dnsimple.py
@@ -9,34 +9,55 @@
import urllib
import re
from BaseHTTPServer import BaseHTTPRequestHandler
-import simplejson as json
+# Update Pythons list of error codes with some that are missing
+newhttpcodes = {
+ 422:('Unprocessable Entity','HTTP_UNPROCESSABLE_ENTITY'),
+ 423:('Locked','HTTP_LOCKED'),
+ 424:('Failed Dependency','HTTP_FAILED_DEPENDENCY'),
+ 425:('No code','HTTP_NO_CODE'),
+ 426:('Upgrade Required','HTTP_UPGRADE_REQUIRED'),
+}
+for code in newhttpcodes:
+ BaseHTTPRequestHandler.responses[code] = newhttpcodes[code]
+import simplejson as json
+import logging
class DNSimple(object):
- def __init__(self,username,password):
- self.endpoint = 'https://dnsimple.com'
- self.authstring = self.getauthstring(self.endpoint,username,password)
- self.useragent = 'DNSimple Python API v20101015'
+ def __init__(self):
+ try:
+ passwordfile = open('.dnsimple').read()
+ username = re.findall(r'username:.*', passwordfile)[0].split(':')[1].strip()
+ password = re.findall(r'password:.*', passwordfile)[0].split(':')[1].strip()
+ except:
+ logging.warn('Could not open .dnsimple file - see README.markdown')
+ exit()
+ self.__endpoint = 'https://dnsimple.com'
+ self.__authstring = self.__getauthstring(self.__endpoint,username,password)
+ self.__useragent = 'DNSimple Python API v20101015'
- def getauthstring(self,endpoint,username,password):
+ def __getauthstring(self,__endpoint,username,password):
encodedstring = base64.encodestring(username+':'+password)[:-1]
return "Basic %s" % encodedstring
- def resthelper(self,url,postdata=None):
+ def __resthelper(self,url,postdata=None):
'''Does GET requests and (if postdata specified) POST requests.
For POSTs we do NOT encode our data, as DNSimple's REST API expects square brackets
which are normally encoded according to RFC 1738. urllib.urlencode encodes square brackets
which the API doesn't like.'''
- url = self.endpoint+url
- request = Request(url, postdata, {"Authorization": self.authstring, "User-Agent": self.useragent })
- result = self.requesthelper(request)
- return json.loads(result)
+ url = self.__endpoint+url
+ request = Request(url, postdata, {"Authorization": self.__authstring, "User-Agent": self.__useragent })
+ result = self.__requesthelper(request)
+ if result:
+ return json.loads(result)
+ else:
+ return None
- def deletehelper(self,url):
+ def __deletehelper(self,url):
'''Does DELETE requests.'''
raise Exception('Not implemented yet')
- def requesthelper(self,request):
+ def __requesthelper(self,request):
'''Does requests and maps HTTP responses into delicious Python juice'''
try:
handle = urlopen(request)
@@ -45,50 +66,49 @@ def requesthelper(self,request):
if hasattr(e, 'reason'):
print 'We failed to reach a server.'
print 'Reason: ', e.reason
+ return
elif hasattr(e, 'code'):
print 'Error code: ', e.code
print '\n'.join(BaseHTTPRequestHandler.responses[e.code])
+ return
else:
return handle.read()
def getdomains(self):
'''Get a list of all domains in your account.'''
- return self.resthelper('/domains.json')
+ return self.__resthelper('/domains.json')
def getdomain(self,domain):
'''Get the details for a specific domain in your account. .'''
- return self.resthelper('/domains/'+domain+'.json')
+ return self.__resthelper('/domains/'+domain+'.json')
def getdomain(self,domain):
'''Get the details for a specific domain in your account. .'''
- return self.resthelper('/domains/'+domain+'.json')
+ return self.__resthelper('/domains/'+domain+'.json')
- def register(self,domainname,registrant_id):
+ def register(self,domainname,registrant_id=None):
'''Register a domain name with DNSimple and the appropriate domain registry. '''
+ if not registrant_id:
+ # Get the registrant ID from the existing domains
+ try:
+ registrant_id = str(self.getdomains()[0]['domain']['registrant_id'])
+ except:
+ print 'Could not find registrant_id! Please specify manually.'
+ exit
postdata = 'domain[name]='+domainname+'&domain[registrant_id]='+registrant_id
- return self.resthelper('/domain_registrations.json', postdata)
+ return self.__resthelper('/domain_registrations.json', postdata)
def transfer(self,domainname,registrant_id):
'''Transfer a domain name from another domain registrar into DNSimple. '''
postdata = 'domain[name]='+domainname+'&domain[registrant_id]='+registrant_id
- return self.resthelper('/domain_transfers.json', postdata)
+ return self.__resthelper('/domain_transfers.json', postdata)
def adddomains(self, domainname):
'''Create a single domain in DNSimple in your account.'''
postdata = 'domain[name]='+domainname
- return self.resthelper('/domains.json', postdata)
+ return self.__resthelper('/domains.json', postdata)
def delete(self,domain):
'''Delete the given domain from your account. You may use either the domain ID or the domain name.'''
- return self.deletehelper('/domains/'+domain+'.json')
-
-
-def main():
- passwordfile = open('.dnsimple').read()
- username = re.findall(r'username:.*', passwordfile)[0].split(':')[1].strip()
- password = re.findall(r'password:.*', passwordfile)[0].split(':')[1].strip()
- dnsimple = DNSimple(username,password)
- print 'You should add some code here - check out the README'
-
-if __name__ == '__main__':
- main()
+ return self.__deletehelper('/domains/'+domain+'.json')
+

0 comments on commit 95c5a2c

Please sign in to comment.
Something went wrong with that request. Please try again.