Is this a Pythonic API design strategy?

Here is the prelude to the question I am asking: I set about creating an API for agnostic gateways for Python for my company. At the moment, I just wrote the code to support Authorize.net and wanted to receive feedback on the clarity of my API design from Python programmers with a little more experience than me.

I chose my own video because other existing packages are more like thoughts about them or specific to Authorize.net (I want to write a more general package with a cleaner interface). I got some inspiration from the package in particular ( pythorize ), but didn't like their API.

Before I begin to describe what I am doing, here is a link to the public repository on the package bitpack: paypy (note for those who can use it: the code is stable, but the documents are very missing).

My current strategy uses a nested dictionary and passes it to the constructor of the payment method class. Example of creating a new user profile in the Authorize.net CIM API:

>>> options = {'tran_key' : 'test_tran_key', ... 'login' : 'developer_login', ... 'testing' : True, ... 'validation': 'testMode', ... 'customer': {'description': 'Some description of the customer profile', ... 'id' : 22, ... 'email' : ' johnny_doe@gmail.com '}, ... 'billing': [{'type': 'individual', ... 'profile': {'city' : 'Carlsbad', ... 'state' : 'California', ... 'zip' : '92009', ... 'firstname' : 'John', ... 'address' : '12 Alicante Rd. Suite 9', ... 'lastname' : 'Doe', ... 'country' : 'USA', ... 'phone' : '(858) 557-2674'}, ... 'payment': {'card': {'ccv' : '524', ... 'number' : '4111111111111111', ... 'expiration' : '2014-04'}}}, ... {'type' : 'individual', ... 'profile' : {'city' : 'Las Vegas', ... 'state' : 'Nevada', ... 'zip' : '79112', ... 'firstname' : 'John', ... 'address' : '78 Cloud Front', ... 'lastname' : 'Doe', ... 'country' : 'USA', ... 'phone' : '(858) 557-2674'}, ... 'payment': {'card': {'ccv' : '499', ... 'number' : '4111111111111111', ... 'expiration' : '2012-11'}}}, ... {'profile': {'city' : 'Carlsbad', ... 'state' : 'California', ... 'zip' : '92009', ... 'firstname' : 'John', ... 'address' : '12 Alicante Rd. Suite 9', ... 'lastname' : 'Doe', ... 'company' : 'Xmarks', ... 'country' : 'USA', ... 'phone' : '(858) 557-2674'}, ... 'payment': {'bank': {'name_on_account' : 'John Doe', ... 'account' : '829330184383', ... 'type' : 'checking', ... 'name' : 'Bank of America', ... 'routing' : '122400724'}}}], ... 'shipping': [{'city' : 'Carlsbad', ... 'state' : 'California', ... 'zip' : '92009', ... 'firstname' : 'John', ... 'address' : '12 Alicante Rd. Suite 9', ... 'lastname' : 'Doe', ... 'country' : 'USA', ... 'phone' : '(858) 557-2674'}]} >>> profile = Profile(options) >>> result = profile.create() >>> result.code 'I00001' >>> print 'Customer Profile ID:' + str(result) Customer Profile ID: 2758851 >>> print 'Customer Payment Profile IDs:' + repr(result.payment_ids) Customer Payment Profile IDs: ['2380878', '2380879', '2380880'] >>> print 'Customer Shipping Profile IDs:' + repr(result.shipping_ids) Customer Shipping Profile IDs: ['2427568'] >>> >>> >>> options = {'id' : str(result), ... 'tran_key' : '86U5pvA9TcxZ5b8D', ... 'testing' : True, ... 'login' : '5b3PhGX68'} >>> profile = Profile(options) >>> result = profile.remove() >>> result.code 'I00001' >>> ^D 

You will notice that I am using a couple of magic methods (e.g. str , etc.) for result objects. I use this dictionary strategy for AIM and ARB methods, and I find out that this is the easiest way to transfer โ€œoptionsโ€ to the payment API, because at some point as an adapter for GoogleCheckout, Paypal, etc. Adapters will be used ...

Another thought I had was to use descriptors and objects instead of dictionaries to pass parameter data to adapters.

As with all payment gateway APIs (in particular, PayPal and Authorize.net), the interfaces are usually a bit messy and in no way standardized, so itโ€™s hard to avoid some gateway-dependent parameters.

+4
source share
1 answer

Deeply nested dictionaries may be non-standard in Python, and maybe then they are "Pythonic", but this is shure, since heck is not a good idea, so I would say that it is not Pythonic.

Instead, I will make a nested class hierarchy. This will be much clearer, IMO, and will also give you the opportunity to conduct type checking.

In fact, I would probably use some kind of circuit module for this.

And how should you enter this data? People reasonably shouldn't have to enter Python code, right?

+3
source

All Articles