Package: python-nfsn
python-nfsnA modern Python library for accessing NearlyFreeSpeech.net’s API.Clean, Pythonic APISupports 100% of NFSN’s API (as of “today” :)Supports Python 2.6 through 3.5Good test coverage (usinghttpretty)Cryptographically secure salt generation withrandom.SystemRandom()InstallingTo get running quickly, install from PyPI:pip install python-nfsnThis will place apynfsnuility in your$PATH.If you want to hack on the code:git clone https://github.com/ktdreyer/python-nfsn
cd python-nfsn
virtualenv venv
. venv/bin/activate
python setup.py developQuickstartObtain your API key from NFSN by submitting a secure support request via the
control panel, and store it in a JSON file in your home directory, like so:$ cat ~/.nfsn-api
{ "login": "ktdreyer",  "api-key": "aGVsbG90aGVyZWZyaWVuZA" }Use thepynfsncommand-line utility, a thin wrapper that lets you explore
the API$ pynfsn member ktdreyer accounts
[u'D41D-8CD98F00', u'B204-E9800998', u'ECF8-427E6D7F']

$ pynfsn member ktdreyer sites
[u'coolsite', u'anothercoolsite']

$ pynfsn dns example.com listRRs www
[{u'data': u'example.nfshost.com.', u'scope': u'system', u'type': u'CNAME', u'name': u'www', u'ttl': u'600'}]

$ pynfsn dns example.com addRR testing A 192.0.2.2

$ pynfsn dns example.com removeRR testing A 192.0.2.2Or use the API directly in your own code:fromnfsnimportNfsnnfsn=Nfsn(login='myusername',api_key='aGVsbG90aGVyZWZyaWVuZA')rrs=nfsn.dns('example.com').listRRs(name='www')forrrinrrs:print(rr['name'])# eg. 'www'print(rr['type'])# eg. 'A'print(rr['data'])# eg. '192.0.2.2'AuthenticationThere are three ways to pass your authentication credentials to theNfsn()constructor:Call the constructor with no arguments:n=Nfsn()By default, the library will look for a$HOME/.nfsn-apiJSON file that
contains your username and API key, like so:$ cat ~/.nfsn-api
{ "login": "ktdreyer",  "api-key": "aGVsbG90aGVyZWZyaWVuZA" }(This matches the same file and format that the Perl NFSN API uses for
authentication, by the way.)Call the constructor with an explicit path to an API key login file:n=Nfsn(login_file='/etc/nfsn-api')In this example, thelogin_fileshould be a JSON file, similar to the
example above.Specify a login string and API key string directly. You can skip the JSON
login_file altogether and just pass the strings you need:n=Nfsn(login='ktdreyer',api_key='aGVsbG90aGVyZWZyaWVuZA')If you do not enter the correct login and key combination, each time you access
a property or method using this library (see below), NearlyFreeSpeech.net will
return a HTTP 401 error, and this library will raise aRuntimeError.API ExamplesSeehttps://members.nearlyfreespeech.net/wiki/APIfor more information.Account APIfromnfsnimportNfsnnfsn=Nfsn(login='ktdreyer',api_key='aGVsbG90aGVyZWZyaWVuZA')# A floating-point value, the balance on the account.# Example: 9.04nfsn.account('A1B2-C3D4E5F6').balance# The friendly, human-readable name for an account.# Example: "Personal" or "Business"nfsn.account('A1B2-C3D4E5F6').friendlyNamenfsn.account('A1B2-C3D4E5F6').friendlyName='Business'# The status details for an account.# Example: { 'color': '#00b000', 'short': 'OK', 'status': 'Ok' }# (Note: returns an AttrDict)nfsn.account('A1B2-C3D4E5F6').status# The sites associated with an account.# Example: [ 'coolsite', 'anothercoolsite' ]nfsn.account('A1B2-C3D4E5F6').sites# Add a new site to an account.nfsn.account('A1B2-C3D4E5F6').addSite(site='testing')# Add a new warning to an account.nfsn.account('A1B2-C3D4E5F6').addWarning(balance=1.23)# Remove a warning from an account.nfsn.account('A1B2-C3D4E5F6').removeWarning(balance=1.23)DNS APIfromnfsnimportNfsnnfsn=Nfsn(login='ktdreyer',api_key='aGVsbG90aGVyZWZyaWVuZA')# Get or set the expiration value for a DNS zone.nfsn.dns('example.com').expire# Example: 86400nfsn.dns('example.com').expire=86401# Get the minTTL value for a DNS zone.# Example: 180nfsn.dns('example.com').minTTL# Get the minTTL value for a DNS zone.# Example: 600nfsn.dns('example.com').refresh# Get the retry value for a DNS zone.# Example: 180nfsn.dns('example.com').retry# Get the serial value for a DNS zone.# Example: 1414129428nfsn.dns('example.com').serial# Add a DNS resource record. The name+type must not exist yet.nfsn.dns('example.com').addRR(name='testing',type='A',data='192.0.2.2')# List all DNS resource records:# (Note: returns an AttrDict)# Example:#    [{'data':  '192.0.2.1',#      'name':  '',#      'scope': 'member',#      'ttl':   '3600',#      'type':  'A'},#     {'data':  'ns.phx2.nearlyfreespeech.net.',#      'name':  '',#      'scope': 'member',#      'ttl':   '3600',#      'type':  'NS'}]nfsn.dns('example.com').listRRs()# List all DNS resource records for 'www.example.com':# (Note: returns an AttrDict)# Example:#    [{'data':  '192.0.2.1',#      'name':  'www',#      'scope': 'member',#      'ttl':   '3600',#      'type':  'A'}]nfsn.dns('example.com').listRRs(name='www')# Add a DNS resource record.# The name+type must exist, or Nfsn will raise an an error. You must# specify all three parameters (name, type, data).nfsn.dns('example.com').removeRR(name='testing',type='A',data='192.0.2.2')Email APIfromnfsnimportNfsnnfsn=Nfsn(login='ktdreyer',api_key='aGVsbG90aGVyZWZyaWVuZA')# List all email forwarding.# Example: { 'hello': 'customerservice@example.net'}# (Note: returns an AttrDict)nfsn.email('example.com').listForwards()# Forward all 'hi@example.com' mail to 'h@example.net':nfsn.email('example.com').setForward(forward='hi',dest_email='h@example.net')# ... And remove the email forward:nfsn.email('example.com').removeForward(forward='hi')Member APIfromnfsnimportNfsnnfsn=Nfsn(login='ktdreyer',api_key='aGVsbG90aGVyZWZyaWVuZA')# Get a list of all accounts belonging to a member.# Example: [ 'A1B2-C3D4E5F6' ]nfsn.member('ktdreyer').accounts# Get a list of all sites belonging to a member.# Example: [ 'coolsite', 'anothercoolsite' ]nfsn.member('ktdreyer').sitesSite APIfromnfsnimportNfsnnfsn=Nfsn(login='ktdreyer',api_key='aGVsbG90aGVyZWZyaWVuZA')# Add or remove an alias for a site:nfsn.site('mycoolsite').addAlias(alias='mobile.example.com')nfsn.site('mycoolsite').removeAlias(alias='mobile.example.com')Types and ErrorsNote that since we useBeanbaginternally, when we return a dict value, it is really anAttrDict. If you want to convert the value to
a plain dict, you will need to use the+operator. Prepend the value with a+sign, like so:rrs=nfsn.dns('example.com').listRRs()print+rrsIf you try to access a non-existent property or method, NearlyFreeSpeech.net
will return a HTTP 404 Not Found error, and this library will raise aBeanBagException.License and CopyrightThis software is CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. SeeCOPYINGfor the full CC0 text.