Skip to content

Commit cde3faa

Browse files
committed
4.42.0
1 parent a16c113 commit cde3faa

16 files changed

Lines changed: 258 additions & 139 deletions

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 4.42.0
4+
* Update requests to not create a new request for every session
5+
* Add `accept_partial_authorization` to Transaction Gateway and `partially_authorized` to Transaction
6+
* Deprecate transactions for `visa_checkout_card` and maintain search functionality
7+
* Add `ach_type` to `options` -> `us_bank_account` in `Transaction.create`
8+
* Add `ach_type` and `requested_ach_type` response fields to `Transaction`
9+
310
## 4.41.0
411
* Add extra fields in `sender` and `receiver` details in `transfer` to `Transaction`
512
* Remove unused error code `AdjustmentAmountMustBeGreaterThanZero`

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,30 @@ else:
6464
print(" message: " + error.message)
6565
```
6666

67+
## Resource Management (Optional)
68+
69+
For long-running applications, you can optionally call `close()` to explicitly release HTTP connections when you're done with a gateway instance:
70+
71+
```python
72+
gateway = braintree.BraintreeGateway(config)
73+
74+
# Process transactions...
75+
result = gateway.transaction.sale({...})
76+
77+
# When completely done with this gateway instance
78+
gateway.close()
79+
```
80+
81+
**When to use `close()`:**
82+
- Long-running web applications that create/destroy gateway instances frequently
83+
- Applications with strict resource management requirements
84+
- High-traffic applications with many concurrent threads
85+
86+
**When you don't need `close()`:**
87+
- Short-lived scripts (resources are cleaned up when the script exits)
88+
- Applications that create a single gateway instance at startup and reuse it
89+
- Most typical use cases (Python's garbage collector handles cleanup automatically)
90+
6791
## Developing
6892

6993
1. Create a [virtualenv](https://virtualenv.pypa.io/) called `venv`:

braintree/braintree_gateway.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ def __init__(self, config=None, **kwargs):
7676
self.verification = CreditCardVerificationGateway(self)
7777
self.webhook_notification = WebhookNotificationGateway(self)
7878
self.webhook_testing = WebhookTestingGateway(self)
79+
80+
def close(self):
81+
if self.config:
82+
self.config.close()

braintree/configuration.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ def graphql_client(self):
127127
def http_strategy(self):
128128
return self._http_strategy
129129

130+
def close(self):
131+
if self._http_strategy:
132+
self._http_strategy.close()
133+
130134
def has_client_credentials(self):
131135
return self.client_secret is not None and self.client_id is not None
132136

braintree/transaction.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def __repr__(self):
139139
"network_transaction_id",
140140
"order_id",
141141
"packages",
142+
"partially_authorized",
142143
"payment_instrument_type",
143144
"payment_method_token",
144145
"plan_id",
@@ -475,6 +476,7 @@ def clone_signature():
475476
@staticmethod
476477
def create_signature():
477478
return [
479+
"accept_partial_authorization",
478480
"account_funding_transaction",
479481
"amount",
480482
# NEXT_MAJOR_VERSION use google_pay_card in public API (map to android_pay_card internally)
@@ -584,6 +586,9 @@ def create_signature():
584586
"venmo": [
585587
"profile_id"
586588
],
589+
"us_bank_account": [
590+
"ach_type"
591+
],
587592
},
588593
{
589594
"adyen": [
@@ -925,6 +930,8 @@ def __init__(self, gateway, attributes):
925930
self.payment_facilitator = PaymentFacilitator(attributes.pop("payment_facilitator"))
926931
if "transfer" in attributes:
927932
self.transfer = Transfer(attributes.pop("transfer"))
933+
if "processor_response_code" in attributes:
934+
self.partially_authorized = attributes["processor_response_code"] == "1004"
928935

929936
@property
930937
def vault_billing_address(self):

braintree/transaction_amounts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ class TransactionAmounts(object):
22
""" A class of constants for transaction amounts that will cause different statuses. """
33

44
Authorize = "1000.00"
5+
PartiallyAuthorized = "1004.00"
56
Decline = "2000.00"
67
HardDecline = "2015.00"
78
Fail = "3000.00"

braintree/util/http.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import sys
2+
import threading
23
import requests
34
from base64 import encodebytes
45
import json
@@ -58,6 +59,17 @@ def raise_exception_from_status(status, message=None):
5859
def __init__(self, config, environment=None):
5960
self.config = config
6061
self.environment = environment or self.config.environment
62+
self._thread_local = threading.local()
63+
64+
def _get_session(self):
65+
if not hasattr(self._thread_local, 'session'):
66+
self._thread_local.session = requests.Session()
67+
return self._thread_local.session
68+
69+
def close(self):
70+
if hasattr(self._thread_local, 'session'):
71+
self._thread_local.session.close()
72+
del self._thread_local.session
6173

6274
def post(self, path, params=None):
6375
return self._make_request("POST", path, Http.ContentType.Xml, params)
@@ -113,22 +125,23 @@ def http_do(self, http_verb, path, headers, request_body):
113125
else:
114126
verify = self.environment.ssl_certificate
115127

116-
with requests.Session() as session:
117-
request = requests.Request(
118-
method=http_verb,
119-
url=full_path,
120-
headers=headers,
121-
data=data,
122-
files=files)
123-
prepared_request = request.prepare()
124-
prepared_request.url = full_path
125-
# there's a bug in requests module that requires we manually update proxy settings,
126-
# see https://github.com/psf/requests/issues/5677
127-
session.proxies.update(requests.utils.getproxies())
128-
129-
response = session.send(prepared_request,
130-
verify=verify,
131-
timeout=self.config.timeout)
128+
session = self._get_session()
129+
130+
request = requests.Request(
131+
method=http_verb,
132+
url=full_path,
133+
headers=headers,
134+
data=data,
135+
files=files)
136+
prepared_request = request.prepare()
137+
prepared_request.url = full_path
138+
# there's a bug in requests module that requires we manually update proxy settings,
139+
# see https://github.com/psf/requests/issues/5677
140+
session.proxies.update(requests.utils.getproxies())
141+
142+
response = session.send(prepared_request,
143+
verify=verify,
144+
timeout=self.config.timeout)
132145

133146
return [response.status_code, response.text]
134147

braintree/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Version = "4.41.0"
1+
Version = "4.42.0"

braintree/visa_checkout_card.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
class VisaCheckoutCard(Resource):
77
"""
8-
A class representing Visa Checkout card
8+
A class representing Visa Checkout card.
9+
10+
DEPRECATED: Visa Checkout is no longer supported for creating new transactions.
11+
This class is retained for search functionality and historical transaction data only.
912
"""
1013
def __init__(self, gateway, attributes):
1114
Resource.__init__(self, gateway, attributes)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
setup(
1414
name="braintree",
15-
version="4.41.0",
15+
version="4.42.0",
1616
description="Braintree Python Library",
1717
long_description=long_description,
1818
author="Braintree",

0 commit comments

Comments
 (0)