Package: bring-api
Bring! Shopping Lists APIAn unofficial python package to access the Bring! shopping lists API.CreditsThis implementation of the api is derived from the generic python implementation byeliasball, which uses the legacy version of the api. This fork has been synced last time on 2024-02-11 and diverges from that point on using the non-legacy version. The implementation ofeliasballis aminimalpython port of thenode-bring-apibyfoxriver76. All credit goes to him for making this awesome API possible!DisclaimerThe developers of this module are in no way endorsed by or affiliated with Bring! Labs AG, or any associated subsidiaries, logos or trademarks.Installationpip install bring-apiDocumentationSee below for usage examples. SeeExceptionsfor API-specific exceptions and mitigation strategies for common exceptions.Usage ExampleThe API is based on the async HTTP libraryaiohttp.importaiohttpimportasyncioimportloggingimportsysfrombring_api.bringimportBringlogging.basicConfig(stream=sys.stdout,level=logging.DEBUG)asyncdefmain():asyncwithaiohttp.ClientSession()assession:# Create Bring instance with email and passwordbring=Bring(session,"MAIL","PASSWORD")# Loginawaitbring.login()# Get information about all available shopping listslists=(awaitbring.load_lists())["lists"]# Save an item with specifications to a certain shopping listawaitbring.save_item(lists[0]['listUuid'],'Milk','low fat')# Save another itemawaitbring.save_item(lists[0]['listUuid'],'Carrots')# Get all the items of a listitems=awaitbring.get_list(lists[0]['listUuid'])print(items)# Check off an itemawaitbring.complete_item(lists[0]['listUuid'],'Carrots')# Remove an item from a listawaitbring.remove_item(lists[0]['listUuid'],'Milk')asyncio.run(main())Manipulating lists withbatch_update_listThis method uses the newer API endpoint for adding, completing and removing items from a list, which is also used in the Bring App. The items can be identified by their uuid and therefore some things are possible that are not possible with the legacy endpoints like:Add/complete/remove multiple items at onceAdding multiple items with the same Name but different specificationsYou can work with a unique identifier for an item even before adding it to a list, just use uuid4 to generate a random uuid!Usage examples:Add an itemWhen adding an item, theitemIdis required,specanduuidare optional. If you need a unique identifier before adding an item, you can just generate a uuid4.item={"itemId":"Cilantro","spec":"fresh","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"}awaitbring.batch_update_list(lists[0]['listUuid'],item,BringItemOperation.ADD)Updating an items specificationWhen updating an item, use ADD operation again. TheitemIdis required and the itemspecwill be added/updated on the existing item on the list. For better matching an existing item (if there is more than one item with the sameitemId), you can use it's unique identifieruuid.item={"itemId":"Cilantro","spec":"dried","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"}awaitbring.batch_update_list(lists[0]['listUuid'],item,BringItemOperation.ADD)Multiple items# multiple items can be passed as list of itemsitems=[{"itemId":"Cilantro","spec":"fresh","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"},{"itemId":"Parsley","spec":"dried","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"}]awaitbring.batch_update_list(lists[0]['listUuid'],items,BringItemOperation.ADD)Add multiple items with the same name but different specifications.When adding items with the same name the parameteruuidis required, otherwise the previous item will be matched byitemIdand it's specification will be overwrittenitems=[{"itemId":"Cilantro","spec":"100g, dried","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"},{"itemId":"Cilantro","spec":"fresh","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"}]awaitbring.batch_update_list(lists[0]['listUuid'],items,BringItemOperation.ADD)Removing or completing an itemWhen removing or completing an item you must submititemIdanduuid,specis optional. Only theuuidwill not work. Leaving out theuuidand submittingitemIdandspecwill also work. When submitting onlyitemIdthe Bring API will match the oldest item.awaitbring.batch_update_list(lists[0]['listUuid'],{"itemId":"Cilantro","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"},BringItemOperation.REMOVE)awaitbring.batch_update_list(lists[0]['listUuid'],{"itemId":"Cilantro","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"},BringItemOperation.COMPLETE)Renaming an item (not recommended)An item that is already on the list can be renamed by sending it'suuidwith a changeditemId. But it is highly advised against it because the Bring App will behave weirdly as it does not refresh an items name, not even when force reloading (going to the top of the list and pulling down). Users have to close the list by going to the overview or closing the app and only then when the list is completely refreshed the change of the name will show up.# Add an itemitem={"itemId":"Cilantro","uuid":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"}awaitbring.batch_update_list(lists[0]['listUuid'],item,BringItemOperation.ADD)# Rename the item, and submit it again with the same uuiditem["itemId"]="Coriander"awaitbring.batch_update_list(lists[0]['listUuid'],item,BringItemOperation.ADD)ExceptionsIn case something goes wrong during a request, several exceptions can be thrown.
They will either be BringRequestException, BringParseException, or BringAuthException, depending on the context. All inherit from BringException.Another asyncio event loop isWith the async calls, you might encounter an error that another asyncio event loop is already running on the same thread. This is expected behavior according to the asyncio.run()documentation. You cannot use more than one aiohttp session per thread, reuse the existing one!Exception ignored: RuntimeError: Event loop is closedDue to a known issue in some versions of aiohttp when using Windows, you might encounter a similar error to this:Exceptionignoredin:<function_ProactorBasePipeTransport.__del__at0x00000000>Traceback(mostrecentcalllast):File"C:\...\py38\lib\asyncio\proactor_events.py",line116,in__del__self.close()File"C:\...\py38\lib\asyncio\proactor_events.py",line108,incloseself._loop.call_soon(self._call_connection_lost,None)File"C:\...\py38\lib\asyncio\base_events.py",line719,incall_soonself._check_closed()File"C:\...\py38\lib\asyncio\base_events.py",line508,in_check_closedraiseRuntimeError('Event loop is closed')RuntimeError:EventloopisclosedYou can fix this according tothisstackoverflow answer by adding the following line of code before executing the library:asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())DevSetup the dev environment using VSCode, is is highly recommended.python-mvenv.venvsource.venv/bin/activate
pipinstall-rrequirements_dev.txtInstallpre-commitpre-commitinstall# Run the commit hooks manuallypre-commitrun--all-files# Run tests locally (using a .env file is supported and recommended)exportEMAIL=...exportPASSWORD=...exportLIST=...
pythontest.pyFollowing VSCode integrations may be helpful:ruffmypyCHANGELOG0.5.4Load article translations from file in executor instead of event loop.0.5.3Improve mypy type checking.0.5.2Fixed build script to add locales explicitly.0.5.1Add article translation tables to package. Translation tables are now loaded from file as data from web app is outdated.0.5.0New API method:batch_update_list. Uses the same API endpoint as the mobile app to add, complete and remove items from shopping lists and has support for uuid as unique identifier for list items.save_item,update_item,complete_itemandremove_itemare now wrapper methods forbatch_update_listand have the additional parameter item_uuid.0.4.1instead of downloading all translation tables, required locales are determined from the user list settings and the user locale. (tr4nt0r)variableuserlistsettingsrenamed to snake_caeuser_list_settings. (tr4nt0r)0.4.0Localization support:catalog items are now automatically translated based on the shopping lists language if configured, otherwise the users default language is used (tr4nt0r)New API method:get_user_account. Retrieves information about the current user like email, name and language (tr4nt0r)New API method:get_all_user_settings. Retrieves user settings like default list and individual list settings for section order and language (tr4nt0r)0.3.1Unpin requirements and remove subdependencies (tr4nt0r)0.3.0Refactor for PEP8 compliance and code clean-up (breaking change) (tr4nt0r)0.2.0Add new method does_user_exist (tr4nt0r)Fixes for test workflow0.1.4Add test workflow.0.1.3Add mypy for type-checking.0.1.2Add ruff as formatter and linter.0.1.1Change name of package tobring-api.0.1.0Test publish workflow for pypi, no code related changes.0.0.1Initial commit based on3.0.0fromeliasball.