GithubHelp home page GithubHelp logo

ponytech / appstoreconnectapi Goto Github PK

View Code? Open in Web Editor NEW
156.0 11.0 73.0 69 KB

Python wrapper around Apple App Store Api

Home Page: https://ponytech.net/projects/app-store-connect

License: MIT License

Python 100.00%

appstoreconnectapi's Introduction

App Store Connect Api

This is a Python wrapper around the Apple App Store Api : https://developer.apple.com/documentation/appstoreconnectapi

So far, it handles token generation / expiration, methods for listing resources and downloading reports.

Installation

Version

The project is published on PyPI, install with:

pip install appstoreconnect

Usage

Please follow instructions on Apple documentation on how to generate an API key.

With your key ID, key file (you can either pass the path to the file or the content of it as a string) and issuer ID create a new API instance:

from appstoreconnect import Api, UserRole
api = Api(key_id, path_to_key_file, issuer_id)

# use a proxy
api = Api(key_id, path_to_key_file, issuer_id, proxy='http://1.2.3.4:3128')

# set a timeout (in seconds) for requests
api = Api(key_id, path_to_key_file, issuer_id, timeout=42)

Here are a few examples of API usage. For a complete list of available methods please see api.py.

# list all apps
apps = api.list_apps()
for app in apps:
    print(app.name, app.sku)

# sort resources
apps = api.list_apps(sort='name')

# filter apps
apps = api.list_apps(filters={'sku': 'DINORUSH', 'name': 'Dino Rush'})
print("%d apps found" % len(apps))

# read app information
app = api.read_app_information('1308363336')
print(app.name, app.sku, app.bundleId)

# get a related resource
for group in app.betaGroups():
    print(group.name)

# list bundle ids
for bundle_id in api.list_bundle_ids():
    print(bundle_id.identifier)

# list certificates
for certificate in api.list_certificates():
    print(certificate.name)

# modify a user
user = api.list_users(filters={'username': '[email protected]'})[0]
api.modify_user_account(user, roles=[UserRole.FINANCE, UserRole.ACCESS_TO_REPORTS])
    
# download sales report
api.download_sales_and_trends_reports(
    filters={'vendorNumber': '123456789', 'frequency': 'WEEKLY', 'reportDate': '2019-06-09'}, save_to='report.csv')

# download finance report
api.download_finance_reports(filters={'vendorNumber': '123456789', 'reportDate': '2019-06'}, save_to='finance.csv')

Define a timeout (in seconds) after which an exception is raised if no response is received.

api = Api(key_id, path_to_key_file, issuer_id, timeout=30)
api.list_apps()

APIError: Read timeout after 30 seconds

Please note this is a work in progress, API is subject to change between versions.

Anonymous data collection

Starting with version 0.8.0 this library anonymously collects its usage to help better improve its development. What we collect is:

  • a SHA1 hash of the issuer_id
  • the OS and Python version used
  • which enpoints had been used

You can review the source code

If you feel uncomfortable with it you can completely opt-out by initliazing the API with:

api = Api(key_id, path_to_key_file, issuer_id, submit_stats=False)

The is also an open issue about this topic where we would love to here your feedback and best practices.

Development

Project development happens on Github

TODO

  • Support App Store Connect API 1.2
  • Support the include parameter
  • handle POST, DELETE and PATCH requests
  • sales report
  • handle related resources
  • allow to sort resources
  • proper API documentation
  • add tests

Credits

This project is developed by Ponytech

appstoreconnectapi's People

Contributors

balestrapatrick avatar conformist-mw avatar ericg-personal avatar fehmitoumi avatar gclunies avatar jaysoffian avatar josepanguera avatar kpotehin avatar ppawlak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

appstoreconnectapi's Issues

can't read localization what's new

image

def read_app_info(): api = Api(AUTH_KEY_ID, AUTH_FILE_PATH, AUTH_ISSUER_ID, submit_stats=True) apps = api.list_apps() for app in apps: print(app.name, app.sku) pre = api.list_beta_build_localizations() x = {v.locale: v.whatsNew for v in pre} print(x)

why the code can read apps, but the beta build localizations are empty?
image
they are all "None", as the first picture shows, I indeed inputted what's new for 'en-US', why is none by my code?
If I get the concept wrong, please point it out. Any help is appreciated.

Can't make request to api when passing variable as argument from file to create it

Hello i've been testing the library for the first time, i was able to do some requests to fetch app info using it but i had some issues when trying to pass the key_id and issuer_id parameters from a file.

If i do this:

ios_api = Api(key_id = "XXXXXXXX", key_file = APPSTORECONNECT_KEY_PATH, issuer_id = "XXXXXXXXXXXXXX")

The library works fine, but if i do this:

f = open(KEY_ID_FILE_PATH, "r")
KEY_ID = f.readline()


f_1 = open(ISSUER_ID_FILE_PATH, "r")
ISSUER_ID = f_1.readline()


ios_api = Api(key_id = KEY_ID, key_file = APPSTORECONNECT_KEY_PATH, issuer_id = ISSUER_ID)
f.close()
f_1.close()
apps = ios_api.list_apps(sort = "name")
for app in apps:
    print(app.name, app.sku)

The output is the following:

Traceback (most recent call last):
  File "appstoreconnect-test.py", line 24, in <module>
    for app in apps:
  File "C:\Users\Seba\.virtualenvs\google-console-api-CfTql0CN\lib\site-packages\appstoreconnect\api.py", line 157, in __next__
    self.fetch_page()
  File "C:\Users\Seba\.virtualenvs\google-console-api-CfTql0CN\lib\site-packages\appstoreconnect\api.py", line 174, in fetch_page
    self.payload = self.api._api_call(self.url)
  File "C:\Users\Seba\.virtualenvs\google-console-api-CfTql0CN\lib\site-packages\appstoreconnect\api.py", line 222, in _api_call
    raise APIError(payload.get('errors', [])[0].get('detail', 'Unknown error'))
appstoreconnect.api.APIError: Provide a properly configured and signed bearer token, and make sure that it has not expired. Learn more about Generating Tokens for API Requests https://developer.apple.com/go/?id=api-generating-tokens

Even though i double checked that the strings KEY_ID and ISSUER_ID are exactly the same that i put manually.
Any help is welcomed, thanks in advance

AttributeError: 'str' object has no attribute 'decode'

Hello,

I have been using this library without issue for a few months. I started encountering an issue since this january 1st.
I'm using the same exact environment and credentials but here is the stacktrace of the exception I am now running into :

AttributeError: 'str' object has no attribute 'decode'
File "batch_reporting.py", line 48, in lambda_handler
issuer_id)
File "appstoreconnect/api.py", line 51, in init
token = self.token # generate first token
File "appstoreconnect/api.py", line 269, in token
self._token = self._generate_token()
File "appstoreconnect/api.py", line 65, in _generate_token
headers={'kid': self.key_id, 'typ': 'JWT'}, algorithm=ALGORITHM).decode('ascii')

The python version is 3.6 and I am using the last version of the library 0.8.4

Do you have any lead on what might cause this ?

Un-hardcode Finance reportType

('reportType', 'FINANCIAL'),

Hi all, not sure if there's any activity here anymore. Thank you for this API! I'd like to use the download_finance_reports function to download FINANCE_DETAIL reports but the value is hardcoded as just FINANCE.

Just curious if there's a reason this is the case? Maybe that wasn't an option when this package was created. Ideally it would just be another filter where I can set the value myself

Bad formatting in api.download_finance_reports() calls

When I run the following code

from appstoreconnect import Api 

key_id = 'foo_bar'
path_to_key_file = './foo_bar.p8'
issuer_id = 'foo_bar'

api = Api(
    key_id,
    path_to_key_filee,
    issuer_id,
    submit_stats=False)

res1 = api.download_finance_reports(
    filters={
        'vendorNumber': '123456789',
        'reportDate': '2020-07',
        'reportType': 'FINANCIAL'
    },
    save_to='test.csv'
)

I get a poorly formatted .csv file. It looks like there is some strange text wrapping going on in the response from api.download_finance_reports(). The response always "wraps" at the Total Rows line. Both the reposnse and .csv show the same problem.

Start Date	End Date	UPC	ISRC/ISBN	Vendor Identifier	Quantity	Partner Share	Extended Partner Share	Partner Share Currency	Sales or Return	Apple Identifier	Artist/Show/Developer/Author	Title	Label/Studio/Network/Developer/Publisher	Grid	Product Type Identifier	ISAN/Other Identifier	Country Of Sale	Pre-order Flag	Promo Code	Customer Price	Customer Currency
03/29/2020	05/02/2020			foobar.iosapp.1month.subscription	1	44.52	44.52	AED	S	123456789		foobar Premium Monthly			IAY		AE			54.99	AED
03/29/2020	05/02/2020			foobar.iosapp.1month.subscription	2	44.52	89.04	AED	S	123456789		foobar Premium Monthly			IAY		AE			54.99	AED
03/29/2020	05/02/2020			foobar.iosapp.1month.subscription	2	36.66	73.32	AED	S	123456789		foobar Premium Monthly			IAY		AE			54.99	AED
...
...
data continues in this pattern
...
...
Total_Rows	262
Country Of Sale	Partner Share Currency	Quantity	Extended Partner Share
AE	AED	7	490.44
AU	AUD	471	14647.84
BR	BRL	113	7988.34

I am trying to work on a fix for this in my use case, but figured I would make you aware how it affects this packages functionality as well.

Can't install on a Mac mini with M2

Hello. I try to install it on a Mac mini with M2 and there is an issue due to your definition of dependency to cryptography

I run just pip install appstoreconnect, and get this:

× Building wheel for cryptography (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [142 lines of output]
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build/lib.macosx-13-arm64-cpython-39
      creating build/lib.macosx-13-arm64-cpython-39/cryptography
      [...]
      writing manifest file 'src/cryptography.egg-info/SOURCES.txt'
      running build_ext
      generating cffi module 'build/temp.macosx-13-arm64-cpython-39/_padding.c'
      creating build/temp.macosx-13-arm64-cpython-39
      generating cffi module 'build/temp.macosx-13-arm64-cpython-39/_constant_time.c'
      generating cffi module 'build/temp.macosx-13-arm64-cpython-39/_openssl.c'
      building '_openssl' extension
      creating build/temp.macosx-13-arm64-cpython-39/build
      creating build/temp.macosx-13-arm64-cpython-39/build/temp.macosx-13-arm64-cpython-39
      clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/opt/homebrew/opt/[email protected]/Frameworks/Python.framework/Versions/3.9/include/python3.9 -c build/temp.macosx-13-arm64-cpython-39/_openssl.c -o build/temp.macosx-13-arm64-cpython-39/build/temp.macosx-13-arm64-cpython-39/_openssl.o -Wconversion -Wno-error=sign-conversion
      build/temp.macosx-13-arm64-cpython-39/_openssl.c:575:10: fatal error: 'openssl/opensslv.h' file not found
      #include <openssl/opensslv.h>
               ^~~~~~~~~~~~~~~~~~~~
      1 error generated.
      error: command '/usr/bin/clang' failed with exit code 1
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for cryptography
ERROR: Could not build wheels for cryptography, which is required to install pyproject.toml-based projects

When it comes to my env:

pip --version
pip 23.1.2 from /opt/homebrew/lib/python3.9/site-packages/pip (python 3.9)

Support PyJWT>=2.0

Main issue is starting with version 2.0.0 jwt.encode() retruns an str whereas older version returns bytes
If not too complex we should support both.

See this issue: #33 (comment)

ImportError: sys.meta_path is None, Python is likely shutting down

I guess there's a problem that Api class requesting the data from the AppStore, but in the end it doesn't close the connection opened. So I'm facing the issue:

Exception ignored in: <function Api.__del__ at 0x7fb0e9e5ba70>
Traceback (most recent call last):
  File "/Users/vladislav/PycharmProjects/sidr_gcp_functions/venv/lib/python3.7/site-packages/appstoreconnect/api.py", line 70, in __del__
  File "/Users/vladislav/PycharmProjects/sidr_gcp_functions/venv/lib/python3.7/site-packages/appstoreconnect/api.py", line 327, in _submit_stats
  File "/Users/vladislav/PycharmProjects/sidr_gcp_functions/venv/lib/python3.7/site-packages/requests/api.py", line 117, in post
  File "/Users/vladislav/PycharmProjects/sidr_gcp_functions/venv/lib/python3.7/site-packages/requests/api.py", line 61, in request
  File "/Users/vladislav/PycharmProjects/sidr_gcp_functions/venv/lib/python3.7/site-packages/requests/sessions.py", line 520, in request
  File "/Users/vladislav/PycharmProjects/sidr_gcp_functions/venv/lib/python3.7/site-packages/requests/sessions.py", line 701, in merge_environment_settings
  File "/Users/vladislav/PycharmProjects/sidr_gcp_functions/venv/lib/python3.7/site-packages/requests/utils.py", line 805, in get_environ_proxies
  File "/Users/vladislav/PycharmProjects/sidr_gcp_functions/venv/lib/python3.7/site-packages/requests/utils.py", line 789, in should_bypass_proxies
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 2645, in proxy_bypass
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 2622, in proxy_bypass_macosx_sysconf
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/urllib/request.py", line 2569, in _proxy_bypass_macosx_sysconf
ImportError: sys.meta_path is None, Python is likely shutting down

Import gc; gc.collect() didn't really help.

Has anyone faced this issue?

Proxy support

Do you have a plan to support proxy setting so that the requests can reach via proxy server?
I didn't try that yet by using your tool but I noticed that I needed to set the proxy to request in my environment as below.

response = requests.get(url, headers=hed, proxies=proxyDict)

If you have this option, would be great. Thanks.

APIError: There were no sales for the date specified. Any way to get Units sold for a free app?

Our app is free so there is no sales - $ sales data, but there is sales - # units data which I am interested in. I am having trouble getting the download_sales_and_trends_reports to return anything because of this. Also, perhaps the script shouldn't crash when there is a day without sales?

I ended up ditching the manual jwt encoding to try your wrapper because I couldn't set the authorization header with String("Bearer ") + Bytes(encoded_jwt). Perhaps you could help me? Thanks

RecursionError when accessing relationships on Build resource

When I try to get preReleaseVersion from Build resource I get:

    app_version = build.preReleaseVersion().version
  File "/usr/local/lib/python3.9/site-packages/appstoreconnect/resources.py", line 16, in __getattr__
    if item in self.relationships:
  File "/usr/local/lib/python3.9/site-packages/appstoreconnect/resources.py", line 16, in __getattr__
    if item in self.relationships:
  File "/usr/local/lib/python3.9/site-packages/appstoreconnect/resources.py", line 16, in __getattr__
    if item in self.relationships:
  [Previous line repeated 993 more times]
  File "/usr/local/lib/python3.9/site-packages/appstoreconnect/resources.py", line 12, in __getattr__
    if item == 'id':
RecursionError: maximum recursion depth exceeded in comparison

I suspect this is caused by Build not having relationships static field, like the other ones.

Python 3.9.2, Version: 0.9.0, I think it was working fine on 0.8.X

How to modify user roles

Hi Pony,
I want to modify an existing user's roles (role and visibleApps), not invite new user. I look from appstore api document, it contain "Modify a User Account" api, but I don't find the related code from your api.py file. would please have a check, thanks very much.

Support "List All In-App Purchases for an App"

Available here:

  1. https://developer.apple.com/documentation/appstoreconnectapi/list_all_in-app_purchases_for_an_app_v1 ("deprecated")
  2. https://developer.apple.com/documentation/appstoreconnectapi/list_all_in-app_purchases_for_an_app (v2)
v1 Example from their page:
{
    "data": [
        {
            "type": "inAppPurchases",
            "id": "ca38ea26-b7d5-4989-9615-c678cb05aabd",
            "attributes": {
                "referenceName": "YNC1",
                "productId": "YNCNC1",
                "inAppPurchaseType": "NON_CONSUMABLE",
                "state": "WAITING_FOR_SCREENSHOT"
            },
            "links": {
                "self": "https://api.appstoreconnect.apple.com/v1/inAppPurchases/ca38ea26-b7d5-4989-9615-c678cb05aabd"
            }
        }
    ],
    "links": {
        "self": "https://api.appstoreconnect.apple.com/v1/apps/6446998023/inAppPurchases"
    },
    "meta": {
        "paging": {
            "total": 1,
            "limit": 50
        }
    }
}

Challenge here seems to be:

  1. the data field being a list instead of dict
  2. the url requires the App ID in the middle of the path
    e.g.: GET https://api.appstoreconnect.apple.com/v1/apps/{id}/inAppPurchases

Invite user giving the API error - new to this library so its basic usage question

Inputs in python code:

any API called as per readme file

Output error

Exception ignored in: <function Api.__del__ at 0x1051eb790>
Traceback (most recent call last):
  File "//user-path...//env/lib/python3.9/site-packages/appstoreconnect/api.py", line 72, in __del__
  File "//user-path...//env/lib/python3.9/site-packages/appstoreconnect/api.py", line 333, in _submit_stats
  File "//user-path...//env/lib/python3.9/site-packages/requests/api.py", line 115, in post
  File "//user-path...//env/lib/python3.9/site-packages/requests/api.py", line 59, in request
  File "//user-path...//env/lib/python3.9/site-packages/requests/sessions.py", line 587, in request
  File "//user-path...//env/lib/python3.9/site-packages/requests/sessions.py", line 701, in send
  File "//user-path...//env/lib/python3.9/site-packages/requests/adapters.py", line 489, in send
  File "//user-path...//env/lib/python3.9/site-packages/urllib3/connectionpool.py", line 703, in urlopen
  File "//user-path...//env/lib/python3.9/site-packages/urllib3/connectionpool.py", line 386, in _make_request
  File "//user-path...//env/lib/python3.9/site-packages/urllib3/connectionpool.py", line 1042, in _validate_conn
  File "//user-path...//env/lib/python3.9/site-packages/urllib3/connection.py", line 380, in connect
ModuleNotFoundError: import of time halted; None in sys.modules

I tried doing pip install time / pip3 install time but the module is not found in the pip command.

% pip3 install time --upgrade
ERROR: Could not find a version that satisfies the requirement time (from versions: none)
ERROR: No matching distribution found for time
WARNING: There was an error checking the latest version of pip.

Include Relationship Data

How do I add the include header in my request so that the response from Apple will have the relationship data?

For example, I am getting all the builds of a particular app by using the following:
https://developer.apple.com/documentation/appstoreconnectapi/list_builds#url

for b in api.list_builds(filters={"app":app_id}, sort="-uploadedDate"):

I'd like to have the appStoreVersion relationship data included in the response so that I can access it by calling b. appStoreVersion.

Financial FINANCE_DETAIL report

Hi, I don't think this is an issue with this wrapper (which is great! thanks!), but maybe you can shed some light:

I'm trying to download the detailed financial report by using download_finance_reports and specifying reportType: FINANCE_DETAIL as per the docs,

But I'm getting there were no sales for the date specified.
Using the default reportType: FINANCIAL works fine.

Am I missing a filter? or is the detailed report not available by the API?
Thanks!

The method download_sales_and_trends_reports is not working (since today)

version: 0.10.0

Actually, the method download_sales_and_trends_reports was working fine until yesterday since last 12 or more months !!

but today, its raising an error with "An unexpected error occurred on the server side. If this issue continues, contact us at https://developer.apple.com/contact/."

For the same credentials, the download_finance_reports works fine.

Sample code

         self.appleapi = appstoreconnect.Api(key_id, private_api_key, issuer_id)
         self.appleapi.download_sales_and_trends_reports(
                filters={
                    'vendorNumber': self.vendor_id,
                    'frequency': 'DAILY',
                    'reportDate': report_date_str
                }

I have written to apple support but have zero hope of receiving a reply from them.

Wondering if its working for you , thank you

Error when use "invite_user"

Hi when I use function "invite_user" ,I got error.

if visible_apps is not None:
			post_data['data']['relationships'] = {'visibleApps': list(map(lambda a: {'id': a, 'type': 'apps'}, visible_apps))}
			post_data['data']['relationships'] = {'visibleApps': visible_apps_relationship}

visible_apps_relationship is not defined . Looks like you forget to the last line.
And just delete post_data['data']['relationships'] = {'visibleApps': visible_apps_relationship} also can not invite user correctly.
I change the code to this and fixed this issue

if visible_apps is not None:
            visible_apps_relationship = list(
                map(lambda a: {'id': a, 'type': 'apps'}, visible_apps))
            visable_apps_data = {'visibleApps': {
                'data': visible_apps_relationship}}
            post_data['data']['relationships'] = visable_apps_data

reportDate change

Maybe someone has encountered this? I receive a report for reportDate - 3 months.
That is, if I pass 2024-04 I get a report for 2024-01, if I pass 2024-05 I get a report for 2024-02.
Very strange.

Code example:

# download finance report
api.download_finance_reports(
    filters={'vendorNumber': '<vendorNumber>', 'reportDate': '2024-05', 'reportType': 'FINANCE_DETAIL', 'regionCode': 'Z1'}, save_to='finance_reports.csv')

Sales reports report type SALES freq DAILY requires version 1_1

There is a bug being discussed here (https://forums.developer.apple.com/forums/thread/745052) regarding this error:

appstoreconnect.api.APIError: The version parameter you have specified is invalid. The latest version for this report is 1_1.

when attempting to download the download_sales_and_trends_reports with a frequency of DAILY.

It looks like the API versions are hard-coded in this repo.

	def download_sales_and_trends_reports(self, filters=None, save_to=None):
		# setup required filters if not provided
		default_versions = {
			'SALES': '1_0',...
		}

https://github.com/Ponytech/appstoreconnectapi/blob/master/appstoreconnect/api.py#L668

If we could get this upgraded to 1_1 that would be fantastic.

on the topic of anonymous data collection

my test suite uses requests_mock to control outgoing requests and this one surprised me when I integrated this library.

>       raise exceptions.NoMockAddress(request)
E       requests_mock.exceptions.NoMockAddress: No mock address: POST https://stats.ponytech.net/new-event

looking in the code:

def _submit_stats(self, event_type):
"""
this submits anonymous usage statistics to help us better understand how this library is used
you can opt-out by initializing the client with submit_stats=False
"""
payload = {
'project': 'appstoreconnectapi',
'version': version,
'type': event_type,
'parameters': {
'python_version': platform.python_version(),
'platform': platform.platform(),
'issuer_id_hash': hashlib.sha1(self.issuer_id.encode()).hexdigest(), # send anonymized hash
}
}
if event_type == 'session_end':
payload['parameters']['endpoints'] = self._call_stats
requests.post('https://stats.ponytech.net/new-event', json.dumps(payload))

I see I can disable this but you should make this opt in, or at least extremely visible in your README.md. I'm using this library to pull financial reports and if I didn't opt into my usage being tracked, I'd be pretty upset down the line to discover this.

I get that its anonymous, but I also didn't opt in to it.

Error when using APP api

Helllo i've been trying to create a template with some info for all my published apps. I wanted to include:

  • App name
  • App build
  • App version on production
  • App version on testflight for external groups
  • App version on testflight for appstoreconnect users
  • Maybe some extra info but for starters that should be ok

So i coded the following:

ios_api = Api(key_id = KEY_ID, key_file = APPSTORECONNECT_KEY_PATH, issuer_id = ISSUER_ID)
apps = ios_api.list_apps(sort = "name")
for app in apps:
    print(app.appStoreVersions())
    for version in app.appStoreVersions():
        print(version)

which returns the following output

Iterator over Resource resource
Traceback (most recent call last):
  File "appstoreconnect-test.py", line 23, in <module>
    for version in app.appStoreVersions():
  File "C:\Users\Seba\.virtualenvs\google-console-api-CfTql0CN\lib\site-packages\appstoreconnect\api.py", line 161, in __next__
    return Resource(data, self.api)
TypeError: Can't instantiate abstract class Resource with abstract methods endpoint

It seems that the Build class doesn't have the atribute added, and so it happens with several other classes, am i correct? or is it that i'm doing something wrong?

Thanks in advance

APIError

Hi,
I have an error when I run the script

this is my script example.py

import sys
from appstoreconnect import Api

if __name__ == "__main__":
        key_id = "XXXXXXXXXX"
        key_file = "AuthKey_XXXXXXXXXX.p8"	
        issuer_id ="XXXXXXXXXX-XXXXX-XXXXXXXXXXXXX"
        
        api = Api(key_id, key_file, issuer_id)
        apps = api.list_apps()

        print (apps)
        for app in apps:
                print(app.name)

The key_file is in the same directory than example.py.
And this is the error

Traceback (most recent call last):
  File "C:\API_apple\example.py", line 26, in <module>
    for app in apps:
  File "C:\API_apple\appstoreconnect\api.py", line 80, in __next__
    self.fetch_page()
  File "C:\API_apple\appstoreconnect\api.py", line 97, in fetch_page
    self.payload = self.api._api_call(self.url)
  File "C:\API_apple\appstoreconnect\api.py", line 135, in _api_call
    raise APIError(payload.get('errors', [])[0].get('detail', 'Unknown error'))
appstoreconnect.api.APIError: Provide a properly configured and signed bearer token, and make sure that it has not expired. Learn more about Generating Tokens for API Requests https://developer.apple.com/go/?id=api-generating-tokens

What is happening ?

Thanks

When listing provisioning files I cannot acces the bundleId

for pro in api.list_profiles():
print(pro.bundleId)

results in:
File "appletest.py", line 48, in
print(pro.bundleId)
File "/Users/leslie/.pyenv/versions/3.7.7/lib/python3.7/site-packages/appstoreconnect/resources.py", line 16, in getattr
if item in self.relationships:
File "/Users/leslie/.pyenv/versions/3.7.7/lib/python3.7/site-packages/appstoreconnect/resources.py", line 16, in getattr
if item in self.relationships:
File "/Users/leslie/.pyenv/versions/3.7.7/lib/python3.7/site-packages/appstoreconnect/resources.py", line 16, in getattr
if item in self.relationships:
[Previous line repeated 496 more times]
RecursionError: maximum recursion depth exceeded

Usage with Python 3.9

Hi, I'm currently hacking on a little project that uses Python 3.9 and I'm having issues trying to use this library. It looks like it depends on the last 2.x version of cryptography, which in turn appears to be incompatible with Python 3.x (if I'm reading the metadata on pypi correctly here). On trying to install appstoreconnectapi using pipenv locally I see the following, which seems to confirm that.

An error occurred while installing cryptography==2.9.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' [...]

I'm a little confused that this project's setup.py contains REQUIRES_PYTHON = '>=3.6.0', so I'm guessing it must be possible somehow? But it's been a few years since I've touched more than a few short lines of Python, so I don't really have the best knowledge around tooling. Any help is much appreciated!

Is there a way to read the error when the API fails?

Is there a way to read the error when the API fails?

I am using the APIs to get user info. But it randomly fails and throws the following error:
" appstoreconnect.api.APIError: An unexpected error occurred on the server side. If this issue continues, contact us at https://developer.apple.com/contact/."

So the API calls fail without any warning or returning any reason.

Adding how to print the error object when the API fails in the example would be helpful.

Accept pull requests?

I needed to get a list of devices associated with an account and your project provided a very nice base for doing that. I forked the project and added the support.

EricG-Personal@12ae8f3

I think I got everything correct (or at least it worked for me). If you would like me to do a pull request, I can and you have one more API implemented.

The api seems to hang if the network is not available.

The api seems to hang if the network is not available. This is probably because there is no timeout specified when making the requests.get() call. Will it make sense to add an optional timeout parameter in the api.

Avoid pinned dependencies

On 8de43ea the dependencies were pinned in setup.py. The problem with that is that now is now longer possible to install this library and, for instance, the latest release of requests alongside.

Since I believe this project has the vocation of being a library and not a standalone project I suggest to instead of pinning the dependencies just force minimum versions*.

I'd be very happy to do a PR if you agree with it.

*I know that jwt 2.* is problematic. For that particular dependency we could just set a minimum and a maximum version.

Basic question on usage

Dear,

Sorry to bother with such a question (I'm a lost R user here) but after after compiling the authentification, I get

Exception ignored in: <function Api.__del__ at 0x7faef65d6670>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/appstoreconnect/api.py", line 72, in __del__
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/appstoreconnect/api.py", line 333, in _submit_stats
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/requests/api.py", line 117, in post
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/requests/api.py", line 61, in request
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/requests/sessions.py", line 529, in request
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/requests/sessions.py", line 645, in send
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/requests/adapters.py", line 440, in send
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/urllib3/connectionpool.py", line 703, in urlopen
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/urllib3/connectionpool.py", line 386, in _make_request
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/urllib3/connectionpool.py", line 1040, in _validate_conn
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/urllib3/connection.py", line 380, in connect
ModuleNotFoundError: import of time halted; None in sys.modules

Process finished with exit code 0

Also, trying to get reporting into PyCharm, I need the Vendorid which is not an obvious parameter to me (where is it?).

Thanks in advance for your help !

Best,
D.

APIError should expose the HTTP status code returned by App Store Connect API response

Happy to take a stab at this @ppawlak.

Issue Description

Ideally, when an APIError exception is raised, the APIerror should also expose the HTTP status code as defined in the Apple docs. I think the best way to do this is to add the HTTP status code as an attribute to the APIError object so that the end user can check against this value.

By exposing the HTTP status code to the end user as an attribute, errors can be maintained as contracts. Currently the only way to check for a APIError is using the error description. Something like...

REPORT_NOT_AVAILABLE_ERROR = (
    "Report is not available yet. Daily reports for the Americas are available"
    " by 5 am Pacific Time; Japan, Australia, and New Zealand by 5 am Japan"
    " Standard Time; and 5 am Central European Time for all other territories."
)
NO_DATA_DATE_SPECIFIED_ERROR = "There were no sales for the date specified."

except APIError as e:
    # Only except certain errors, full list of possible errors is found here: 
    # https://developer.apple.com/documentation/appstoreconnectapi/interpreting_and_handling_errors/about_the_http_status_code  # noqa
    if str(e) == REPORT_NOT_AVAILABLE_ERROR or str(e) == NO_DATA_DATE_SPECIFIED_ERROR:
        LOGGER.error("{0}".format(e))
    else:
        raise e

If Apple changes the error description slightly this approach will break. I would expect the HTTP status codes to be much more stable.

Provide a properly configured and signed bearer token, and make sure that it has not expired.

I just installed this yesterday and it worked fine. But today it starts throw error "Provide a properly configured and signed bearer token, and make sure that it has not expired. Learn more about Generating Tokens for API Requests https://developer.apple.com/go/?id=api-generating-tokens".

At the end I found out it maybe caused by the expiration time. When I changed it from 20 to 15, it works again:
exp = int(time.mktime((self.token_gen_date + timedelta(minutes=15)).timetuple()))
On documentation here: https://developer.apple.com/documentation/appstoreconnectapi/generating_tokens_for_api_requests it says Tokens that expire more than 20 minutes into the future are not valid so I guess when do the calculation with 20 mins it may round up to exceed 20 mins?

Updated: after I sync the time on my PC, it works again with 20mins.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.