pymobiledevice3 6.2.0__tar.gz → 7.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/workflows/python-app.yml +1 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/PKG-INFO +3 -2
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/__main__.py +139 -44
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/_version.py +3 -3
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/bonjour.py +19 -20
- pymobiledevice3-7.0.1/pymobiledevice3/cli/activation.py +46 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/afc.py +64 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/amfi.py +33 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/apps.py +104 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/backup.py +241 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/bonjour.py +31 -29
- pymobiledevice3-7.0.1/pymobiledevice3/cli/cli_common.py +313 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/companion_proxy.py +22 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/crash.py +131 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/__init__.py +62 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/arbitration.py +50 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/condition.py +33 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/core_device.py +294 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/debugserver.py +244 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/dvt/__init__.py +387 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/developer/simulate_location.py +51 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/diagnostics/__init__.py +75 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/diagnostics/battery.py +47 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/idam.py +42 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/lockdown.py +190 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/mounter.py +99 -57
- pymobiledevice3-7.0.1/pymobiledevice3/cli/notification.py +68 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/pcap.py +36 -20
- pymobiledevice3-7.0.1/pymobiledevice3/cli/power_assertion.py +26 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/processes.py +11 -17
- pymobiledevice3-7.0.1/pymobiledevice3/cli/profile.py +236 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/provision.py +59 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/remote.py +108 -99
- pymobiledevice3-7.0.1/pymobiledevice3/cli/restore.py +252 -0
- pymobiledevice3-7.0.1/pymobiledevice3/cli/springboard.py +90 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/syslog.py +138 -74
- pymobiledevice3-7.0.1/pymobiledevice3/cli/usbmux.py +108 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/version.py +2 -5
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/webinspector.py +149 -103
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/exceptions.py +4 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/lockdown.py +1 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/remote_service_discovery.py +14 -10
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/device.py +28 -4
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/service_connection.py +1 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/mobilebackup2.py +4 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/screenshot.py +2 -2
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/automation_session.py +4 -2
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/cdp_screencast.py +2 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/element.py +3 -3
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3.egg-info/PKG-INFO +3 -2
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3.egg-info/SOURCES.txt +16 -3
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3.egg-info/requires.txt +2 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pyproject.toml +20 -6
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pytest.ini +1 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/requirements.txt +2 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/cli/test_cli.py +4 -4
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/conftest.py +3 -7
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/instruments/test_core_profile_session.py +2 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/instruments/test_dvt_secure_socket_proxy.py +13 -14
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/instruments/test_fetch_symbols.py +4 -5
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/instruments/test_location.py +4 -5
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/instruments/test_screenshot.py +2 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_accessibility.py +4 -3
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_afc.py +31 -30
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_apps.py +3 -2
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_backup2.py +3 -3
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_bonjour.py +4 -3
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_crash_reports.py +9 -9
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_house_arrest.py +1 -1
- pymobiledevice3-7.0.1/tests/services/test_list_devices.py +6 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_lockdown.py +3 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_pcapd.py +2 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_springboard_services_relay.py +4 -3
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_start_tunnel.py +1 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_syslog_relay.py +2 -1
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_tcp_forwarder.py +2 -2
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_web_protocol/test_element.py +3 -2
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_webinspector.py +2 -1
- pymobiledevice3-6.2.0/pymobiledevice3/cli/activation.py +0 -44
- pymobiledevice3-6.2.0/pymobiledevice3/cli/afc.py +0 -56
- pymobiledevice3-6.2.0/pymobiledevice3/cli/amfi.py +0 -38
- pymobiledevice3-6.2.0/pymobiledevice3/cli/apps.py +0 -98
- pymobiledevice3-6.2.0/pymobiledevice3/cli/backup.py +0 -200
- pymobiledevice3-6.2.0/pymobiledevice3/cli/cli_common.py +0 -366
- pymobiledevice3-6.2.0/pymobiledevice3/cli/companion_proxy.py +0 -22
- pymobiledevice3-6.2.0/pymobiledevice3/cli/completions.py +0 -50
- pymobiledevice3-6.2.0/pymobiledevice3/cli/crash.py +0 -88
- pymobiledevice3-6.2.0/pymobiledevice3/cli/developer.py +0 -1645
- pymobiledevice3-6.2.0/pymobiledevice3/cli/diagnostics.py +0 -110
- pymobiledevice3-6.2.0/pymobiledevice3/cli/idam.py +0 -46
- pymobiledevice3-6.2.0/pymobiledevice3/cli/lockdown.py +0 -195
- pymobiledevice3-6.2.0/pymobiledevice3/cli/notification.py +0 -56
- pymobiledevice3-6.2.0/pymobiledevice3/cli/power_assertion.py +0 -27
- pymobiledevice3-6.2.0/pymobiledevice3/cli/profile.py +0 -191
- pymobiledevice3-6.2.0/pymobiledevice3/cli/provision.py +0 -58
- pymobiledevice3-6.2.0/pymobiledevice3/cli/restore.py +0 -247
- pymobiledevice3-6.2.0/pymobiledevice3/cli/springboard.py +0 -90
- pymobiledevice3-6.2.0/pymobiledevice3/cli/usbmux.py +0 -69
- pymobiledevice3-6.2.0/tests/services/test_list_devices.py +0 -5
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.gitattributes +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/FUNDING.yml +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/pull_request_template.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/workflows/codeql.yml +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/workflows/generate-executable.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/workflows/markdown-lint.yml +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.github/workflows/python-publish.yml +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.gitignore +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/.pre-commit-config.yaml +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/CODE_OF_CONDUCT.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/CONTRIBUTING.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/LICENSE +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/README.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/example.gif +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/markdownlint-config.json +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/misc/DTServices-14.2.txt +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/misc/DTServices-14.5.txt +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/misc/RemoteXPC.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/misc/plist_sniffer.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/misc/pyinstaller.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/misc/remotexpc_sniffer.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/misc/understanding_idevice_protocol_layers.md +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/misc/usbmux_sniff.sh +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/ca.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/cli/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/common.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/irecv.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/irecv_devices.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/lockdown_service_provider.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/osu/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/osu/os_utils.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/osu/posix_util.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/osu/win_util.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/pair_records.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/common.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/core_device/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/core_device/app_service.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/core_device/core_device_service.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/core_device/device_info.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/core_device/diagnostics_service.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/core_device/file_service.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/module_imports.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/remote_service.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/remotexpc.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/tunnel_service.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/utils.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/remote/xpc_message.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/dsc_uuid_map.json +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/dsc_uuid_map.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/firmware_notifications.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/notifications.txt +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/element_attribute.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/element_clear.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/enter_fullscreen.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/find_nodes.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/focus.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/get_attribute.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/is_displayed.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/is_editable.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/resources/webinspector/is_enabled.js +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/asr.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/base_restore.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/consts.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/fdr.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/ftab.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/img4.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/mbn.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/recovery.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/restore.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/restore_options.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/restored_client.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/restore/tss.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/accessibilityaudit.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/afc.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/amfi.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/companion.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/crash_reports.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/debugserver_applist.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/device_arbitration.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/device_link.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/diagnostics.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dtfetchsymbols.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/application_listing.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/condition_inducer.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/device_info.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/energy_monitor.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/graphics.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/location_simulation.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/location_simulation_base.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/network_monitor.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/notifications.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/process_control.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/screenshot.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/instruments/sysmontap.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/dvt/testmanaged/xcuitest.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/file_relay.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/heartbeat.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/house_arrest.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/idam.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/installation_proxy.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/lockdown_service.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/misagent.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/mobile_activation.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/mobile_config.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/mobile_image_mounter.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/notification_proxy.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/os_trace.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/pcapd.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/power_assertion.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/preboard.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/remote_fetch_symbols.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/remote_server.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/restore_service.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/simulate_location.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/springboard.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/syslog.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/alert.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/cdp_server.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/cdp_target.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/driver.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/inspector_session.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/selenium_api.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/session_protocol.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/web_protocol/switch_to.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/services/webinspector.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/tcp_forwarder.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/tunneld/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/tunneld/api.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/tunneld/server.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/usbmux.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3/utils.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3.egg-info/dependency_links.txt +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3.egg-info/entry_points.txt +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/pymobiledevice3.egg-info/top_level.txt +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/setup.cfg +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/cli/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/instruments/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_web_protocol/__init__.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_web_protocol/common.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_web_protocol/conftest.py +0 -0
- {pymobiledevice3-6.2.0 → pymobiledevice3-7.0.1}/tests/services/test_web_protocol/test_driver.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pymobiledevice3
|
|
3
|
-
Version:
|
|
3
|
+
Version: 7.0.1
|
|
4
4
|
Summary: Pure python3 implementation for working with iDevices (iPhone, etc...)
|
|
5
5
|
Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
|
|
6
6
|
Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
|
|
@@ -23,7 +23,6 @@ License-File: LICENSE
|
|
|
23
23
|
Requires-Dist: construct>=2.9.29
|
|
24
24
|
Requires-Dist: construct-typing>=0.7.0
|
|
25
25
|
Requires-Dist: asn1
|
|
26
|
-
Requires-Dist: click
|
|
27
26
|
Requires-Dist: coloredlogs
|
|
28
27
|
Requires-Dist: IPython
|
|
29
28
|
Requires-Dist: bpylist2>=4.0.1
|
|
@@ -61,6 +60,8 @@ Requires-Dist: sslpsk-pmd3>=1.0.3; python_version < "3.13"
|
|
|
61
60
|
Requires-Dist: python-pcapng>=2.1.1
|
|
62
61
|
Requires-Dist: plumbum
|
|
63
62
|
Requires-Dist: pyimg4>=0.8.8
|
|
63
|
+
Requires-Dist: typer>=0.20.0
|
|
64
|
+
Requires-Dist: typer-injector>=0.2.0
|
|
64
65
|
Provides-Extra: test
|
|
65
66
|
Requires-Dist: pytest; extra == "test"
|
|
66
67
|
Requires-Dist: pytest-asyncio; extra == "test"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import difflib
|
|
3
|
+
import importlib
|
|
3
4
|
import logging
|
|
4
5
|
import os
|
|
5
6
|
import re
|
|
@@ -7,13 +8,18 @@ import sys
|
|
|
7
8
|
import textwrap
|
|
8
9
|
import traceback
|
|
9
10
|
import warnings
|
|
10
|
-
from
|
|
11
|
+
from collections.abc import Sequence
|
|
12
|
+
from typing import Annotated, Optional, Union
|
|
11
13
|
|
|
12
14
|
import click
|
|
13
15
|
import coloredlogs
|
|
16
|
+
import typer
|
|
17
|
+
import typer.core
|
|
14
18
|
from packaging.version import Version
|
|
19
|
+
from typer.core import TyperGroup
|
|
20
|
+
from typer_injector import InjectingTyper
|
|
15
21
|
|
|
16
|
-
from pymobiledevice3.cli.cli_common import TUNNEL_ENV_VAR, isatty
|
|
22
|
+
from pymobiledevice3.cli.cli_common import TUNNEL_ENV_VAR, isatty, set_color_flag, set_verbosity
|
|
17
23
|
from pymobiledevice3.exceptions import (
|
|
18
24
|
AccessDeniedError,
|
|
19
25
|
CloudConfigurationAlreadyPresentError,
|
|
@@ -38,6 +44,7 @@ from pymobiledevice3.exceptions import (
|
|
|
38
44
|
QuicProtocolNotSupportedError,
|
|
39
45
|
RSDRequiredError,
|
|
40
46
|
SetProhibitedError,
|
|
47
|
+
StartServiceError,
|
|
41
48
|
TunneldConnectionError,
|
|
42
49
|
UserDeniedPairingError,
|
|
43
50
|
)
|
|
@@ -112,25 +119,26 @@ CLI_GROUPS = {
|
|
|
112
119
|
"webinspector": "webinspector",
|
|
113
120
|
"idam": "idam",
|
|
114
121
|
"version": "version",
|
|
115
|
-
"install-completions": "completions",
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
# Set if used the `--reconnect` option
|
|
119
125
|
RECONNECT = False
|
|
120
126
|
|
|
121
127
|
|
|
122
|
-
class
|
|
123
|
-
def list_commands(self, ctx):
|
|
124
|
-
|
|
128
|
+
class Pmd3TyperGroup(TyperGroup):
|
|
129
|
+
def list_commands(self, ctx: click.Context) -> list[str]:
|
|
130
|
+
# Order is preserved by dict insertion; adjust if you want alphabetical
|
|
131
|
+
return list(CLI_GROUPS.keys())
|
|
125
132
|
|
|
126
|
-
def get_command(self, ctx: click.Context,
|
|
127
|
-
if
|
|
128
|
-
self.handle_invalid_command(ctx,
|
|
129
|
-
return self.import_and_get_command(ctx,
|
|
133
|
+
def get_command(self, ctx: click.Context, cmd_name: str) -> click.Command:
|
|
134
|
+
if cmd_name not in CLI_GROUPS:
|
|
135
|
+
self.handle_invalid_command(ctx, cmd_name)
|
|
136
|
+
return self.import_and_get_command(ctx, cmd_name)
|
|
130
137
|
|
|
131
|
-
def handle_invalid_command(self, ctx
|
|
138
|
+
def handle_invalid_command(self, ctx, name: str) -> None:
|
|
132
139
|
suggested_commands = self.search_commands(name)
|
|
133
140
|
suggestion = self.format_suggestions(suggested_commands)
|
|
141
|
+
# ctx.fail raises a ClickException underneath, which Typer displays nicely
|
|
134
142
|
ctx.fail(f"No such command {name!r}{suggestion}")
|
|
135
143
|
|
|
136
144
|
@staticmethod
|
|
@@ -138,70 +146,109 @@ class Pmd3Cli(click.Group):
|
|
|
138
146
|
if not suggestions:
|
|
139
147
|
return ""
|
|
140
148
|
cmds = textwrap.indent("\n".join(suggestions), " " * 4)
|
|
141
|
-
return f"\nDid you mean
|
|
149
|
+
return f"\nDid you mean:\n{cmds}"
|
|
142
150
|
|
|
143
151
|
@staticmethod
|
|
144
152
|
def import_and_get_command(ctx: click.Context, name: str) -> click.Command:
|
|
145
153
|
module_name = f"pymobiledevice3.cli.{CLI_GROUPS[name]}"
|
|
146
|
-
mod =
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
command = mod.cli.get_command(ctx, command_name)
|
|
151
|
-
return command
|
|
154
|
+
mod = importlib.import_module(module_name)
|
|
155
|
+
# submodules expose a Typer Group named "cli"
|
|
156
|
+
cli: typer.Typer = mod.cli
|
|
157
|
+
return typer.main.get_command(cli)
|
|
152
158
|
|
|
153
159
|
@staticmethod
|
|
154
160
|
def highlight_keyword(text: str, keyword: str) -> str:
|
|
155
|
-
return re.sub(f"({keyword})",
|
|
161
|
+
return re.sub(f"({keyword})", typer.style("\\1", bold=True), text, flags=re.IGNORECASE)
|
|
156
162
|
|
|
157
163
|
@staticmethod
|
|
158
|
-
def collect_commands(command: click.Command) -> Union[str, list[str]]:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
for
|
|
162
|
-
|
|
163
|
-
if isinstance(
|
|
164
|
-
|
|
164
|
+
def collect_commands(command: Union[TyperGroup, click.Command]) -> Union[str, list[str]]:
|
|
165
|
+
if isinstance(command, TyperGroup): # group
|
|
166
|
+
cmds = []
|
|
167
|
+
for v in command.commands.values():
|
|
168
|
+
child = Pmd3TyperGroup.collect_commands(v)
|
|
169
|
+
if isinstance(child, list):
|
|
170
|
+
cmds.extend([f"{command.name} {c}" for c in child])
|
|
165
171
|
else:
|
|
166
|
-
|
|
167
|
-
return
|
|
168
|
-
return
|
|
172
|
+
cmds.append(f"{command.name} {child}")
|
|
173
|
+
return cmds
|
|
174
|
+
return command.name or ""
|
|
169
175
|
|
|
170
176
|
@staticmethod
|
|
171
177
|
def search_commands(pattern: str) -> list[str]:
|
|
172
|
-
all_commands =
|
|
178
|
+
all_commands = Pmd3TyperGroup.load_all_commands()
|
|
173
179
|
matched = sorted(filter(lambda cmd: re.search(pattern, cmd), all_commands))
|
|
174
180
|
if not matched:
|
|
175
181
|
matched = difflib.get_close_matches(pattern, all_commands, n=20, cutoff=0.4)
|
|
176
182
|
if isatty():
|
|
177
|
-
matched = [
|
|
183
|
+
matched = [Pmd3TyperGroup.highlight_keyword(cmd, pattern) for cmd in matched]
|
|
178
184
|
return matched
|
|
179
185
|
|
|
180
186
|
@staticmethod
|
|
181
187
|
def load_all_commands() -> list[str]:
|
|
182
|
-
all_commands = []
|
|
188
|
+
all_commands: list[str] = []
|
|
183
189
|
for key in CLI_GROUPS:
|
|
184
190
|
module_name = f"pymobiledevice3.cli.{CLI_GROUPS[key]}"
|
|
185
|
-
mod =
|
|
186
|
-
|
|
191
|
+
mod = importlib.import_module(module_name)
|
|
192
|
+
if isinstance(mod.cli, typer.Typer):
|
|
193
|
+
cmd = Pmd3TyperGroup.collect_commands(typer.main.get_group(mod.cli))
|
|
194
|
+
else:
|
|
195
|
+
cmd = Pmd3TyperGroup.collect_commands(mod.cli.commands[key])
|
|
187
196
|
if isinstance(cmd, list):
|
|
188
197
|
all_commands.extend(cmd)
|
|
189
198
|
else:
|
|
190
199
|
all_commands.append(cmd)
|
|
191
200
|
return all_commands
|
|
192
201
|
|
|
202
|
+
def resolve_command(
|
|
203
|
+
self, ctx: click.Context, args: list[str]
|
|
204
|
+
) -> tuple[Optional[str], Optional[click.Command], list[str]]:
|
|
205
|
+
return super().resolve_command(ctx, args)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
app = InjectingTyper(
|
|
209
|
+
cls=Pmd3TyperGroup,
|
|
210
|
+
context_settings=CONTEXT_SETTINGS,
|
|
211
|
+
no_args_is_help=True,
|
|
212
|
+
# add_completion=False,
|
|
213
|
+
rich_markup_mode="markdown",
|
|
214
|
+
help=(
|
|
215
|
+
"Swiss-army CLI for pairing, inspecting, backing up, and automating iOS devices.\n\n"
|
|
216
|
+
"Docs and examples: https://github.com/doronz88/pymobiledevice3"
|
|
217
|
+
),
|
|
218
|
+
)
|
|
219
|
+
|
|
193
220
|
|
|
194
|
-
@
|
|
195
|
-
|
|
196
|
-
|
|
221
|
+
@app.callback()
|
|
222
|
+
def _root(
|
|
223
|
+
reconnect: Annotated[
|
|
224
|
+
bool,
|
|
225
|
+
typer.Option(
|
|
226
|
+
"--reconnect",
|
|
227
|
+
help="Automatically reconnect if the device disconnects mid-command.",
|
|
228
|
+
show_default=False,
|
|
229
|
+
),
|
|
230
|
+
] = False,
|
|
231
|
+
verbosity: Annotated[
|
|
232
|
+
int,
|
|
233
|
+
typer.Option(
|
|
234
|
+
"--verbose",
|
|
235
|
+
"-v",
|
|
236
|
+
count=True,
|
|
237
|
+
help="Increase logging verbosity (repeat for more detail).",
|
|
238
|
+
),
|
|
239
|
+
] = 0,
|
|
240
|
+
color: Annotated[
|
|
241
|
+
bool,
|
|
242
|
+
typer.Option(help="Colorize output; disable with --no-color for plain logs."),
|
|
243
|
+
] = True,
|
|
244
|
+
) -> None:
|
|
197
245
|
"""
|
|
198
|
-
|
|
199
|
-
Interact with a connected iDevice (iPhone, iPad, ...)
|
|
200
|
-
For more information please look at:
|
|
201
|
-
https://github.com/doronz88/pymobiledevice3
|
|
246
|
+
Top-level options for pymobiledevice3.
|
|
202
247
|
"""
|
|
203
248
|
global RECONNECT
|
|
204
249
|
RECONNECT = reconnect
|
|
250
|
+
set_verbosity(verbosity)
|
|
251
|
+
set_color_flag(color)
|
|
205
252
|
|
|
206
253
|
|
|
207
254
|
def device_might_need_tunneld(identifier: str) -> bool:
|
|
@@ -221,13 +268,53 @@ def device_might_need_tunneld(identifier: str) -> bool:
|
|
|
221
268
|
return Version(lockdown.product_version) >= Version("17.0")
|
|
222
269
|
|
|
223
270
|
|
|
271
|
+
class PossiblyMisplacedOption(click.NoSuchOption):
|
|
272
|
+
def __init__(
|
|
273
|
+
self,
|
|
274
|
+
option_name: str,
|
|
275
|
+
message: Optional[str] = None,
|
|
276
|
+
possibilities: Optional[Sequence[str]] = None,
|
|
277
|
+
ctx: Optional[click.Context] = None,
|
|
278
|
+
suggested_ctx: Optional[click.Context] = None,
|
|
279
|
+
) -> None:
|
|
280
|
+
super().__init__(option_name, message, possibilities, ctx)
|
|
281
|
+
if suggested_ctx is not None:
|
|
282
|
+
if ctx is not None:
|
|
283
|
+
self.message += f" for subcommand: {ctx.command_path}"
|
|
284
|
+
|
|
285
|
+
suggestion = f"{suggested_ctx.command_path} {option_name}"
|
|
286
|
+
suggestion += ctx.command_path.removeprefix(suggested_ctx.command_path) if ctx is not None else " ..."
|
|
287
|
+
|
|
288
|
+
self.message += f"\nDid you mean: {suggestion}?"
|
|
289
|
+
|
|
290
|
+
@staticmethod
|
|
291
|
+
def from_no_such_option(e: click.NoSuchOption) -> "PossiblyMisplacedOption":
|
|
292
|
+
ctx = e.ctx
|
|
293
|
+
while ctx:
|
|
294
|
+
for param in ctx.command.params:
|
|
295
|
+
if isinstance(param, typer.core.TyperOption) and (
|
|
296
|
+
e.option_name in param.opts or e.option_name in param.secondary_opts
|
|
297
|
+
):
|
|
298
|
+
break
|
|
299
|
+
else:
|
|
300
|
+
ctx = ctx.parent
|
|
301
|
+
continue
|
|
302
|
+
break
|
|
303
|
+
|
|
304
|
+
return PossiblyMisplacedOption(e.option_name, e.message, e.possibilities, e.ctx, ctx)
|
|
305
|
+
|
|
306
|
+
|
|
224
307
|
def invoke_cli_with_error_handling() -> bool:
|
|
225
308
|
"""
|
|
226
309
|
Invoke the command line interface and return `True` if the failure reason of the command was that the device was
|
|
227
310
|
disconnected.
|
|
228
311
|
"""
|
|
229
312
|
try:
|
|
230
|
-
|
|
313
|
+
# Typer apps are callable; this executes the CLI with current sys.argv
|
|
314
|
+
try:
|
|
315
|
+
app(standalone_mode=False)
|
|
316
|
+
except click.NoSuchOption as e:
|
|
317
|
+
raise PossiblyMisplacedOption.from_no_such_option(e) from e
|
|
231
318
|
except NoDeviceConnectedError:
|
|
232
319
|
logger.error("Device is not connected")
|
|
233
320
|
return True
|
|
@@ -277,9 +364,10 @@ def invoke_cli_with_error_handling() -> bool:
|
|
|
277
364
|
logger.warning("Got an InvalidServiceError. Trying again over tunneld since it is a developer command")
|
|
278
365
|
should_retry_over_tunneld = True
|
|
279
366
|
if should_retry_over_tunneld:
|
|
280
|
-
# use a single space because
|
|
367
|
+
# use a single space because Typer/Click will ignore envvars of empty strings
|
|
281
368
|
os.environ[TUNNEL_ENV_VAR] = e.identifier or " "
|
|
282
|
-
|
|
369
|
+
main()
|
|
370
|
+
return False
|
|
283
371
|
logger.error(INVALID_SERVICE_MESSAGE)
|
|
284
372
|
except PasswordRequiredError:
|
|
285
373
|
logger.error("Device is password protected. Please unlock and retry")
|
|
@@ -315,6 +403,13 @@ def invoke_cli_with_error_handling() -> bool:
|
|
|
315
403
|
)
|
|
316
404
|
except QuicProtocolNotSupportedError:
|
|
317
405
|
logger.error("Encountered a QUIC protocol error.")
|
|
406
|
+
except StartServiceError as e:
|
|
407
|
+
logger.error(f"Failed to start: {e.service_name} with. Received error: {e.message}.")
|
|
408
|
+
except click.ClickException as e:
|
|
409
|
+
from typer import rich_utils
|
|
410
|
+
|
|
411
|
+
rich_utils.rich_format_error(e)
|
|
412
|
+
sys.exit(e.exit_code)
|
|
318
413
|
|
|
319
414
|
return False
|
|
320
415
|
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '
|
|
32
|
-
__version_tuple__ = version_tuple = (
|
|
31
|
+
__version__ = version = '7.0.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (7, 0, 1)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g7ca380f05'
|
|
@@ -300,10 +300,9 @@ async def browse_service(service_type: str, timeout: float = 4.0) -> list[Servic
|
|
|
300
300
|
adapters = _Adapters()
|
|
301
301
|
|
|
302
302
|
ptr_targets: set[str] = set()
|
|
303
|
-
srv_map: dict[str, dict] = {}
|
|
303
|
+
srv_map: dict[str, list[dict]] = defaultdict(list) # instance_name -> list of {"target", "port"}
|
|
304
304
|
txt_map: dict[str, dict] = {}
|
|
305
|
-
# host -> list[(ip, iface)]
|
|
306
|
-
host_addrs: dict[str, list[Address]] = defaultdict(list)
|
|
305
|
+
host_addrs: dict[str, list[Address]] = defaultdict(list) # host -> list[(ip, iface)]
|
|
307
306
|
|
|
308
307
|
def _record_addr(rr_name: str, ip_str: str, pkt_addr):
|
|
309
308
|
# Determine family and possible scopeid from the packet that delivered this RR
|
|
@@ -314,7 +313,7 @@ async def browse_service(service_type: str, timeout: float = 4.0) -> list[Servic
|
|
|
314
313
|
iface = adapters.pick_iface_for_ip(ip_str, family, scopeid)
|
|
315
314
|
if iface is None:
|
|
316
315
|
return
|
|
317
|
-
#
|
|
316
|
+
# Avoid duplicates for the same host/ip
|
|
318
317
|
existing = host_addrs[rr_name]
|
|
319
318
|
if not any(a.ip == ip_str for a in existing):
|
|
320
319
|
existing.append(Address(ip=ip_str, iface=iface))
|
|
@@ -333,11 +332,10 @@ async def browse_service(service_type: str, timeout: float = 4.0) -> list[Servic
|
|
|
333
332
|
if t == QTYPE_PTR and rr.get("name") == service_type:
|
|
334
333
|
ptr_targets.add(rr.get("ptrdname"))
|
|
335
334
|
elif t == QTYPE_SRV:
|
|
336
|
-
srv_map[rr["name"]]
|
|
337
|
-
"target": rr.get("target"),
|
|
338
|
-
"port": rr.get("port"),
|
|
339
|
-
}
|
|
335
|
+
srv_map[rr["name"]].append({"target": rr.get("target"), "port": rr.get("port")})
|
|
340
336
|
elif t == QTYPE_TXT:
|
|
337
|
+
# TODO: This could possibly mix the properties of multiple TXT records for the same instance.
|
|
338
|
+
# However, it's currently unused.
|
|
341
339
|
txt_map[rr["name"]] = rr.get("txt", {})
|
|
342
340
|
elif (t == QTYPE_A and rr.get("address")) or (t == QTYPE_AAAA and rr.get("address")):
|
|
343
341
|
_record_addr(rr["name"], rr["address"], pkt_addr)
|
|
@@ -348,20 +346,21 @@ async def browse_service(service_type: str, timeout: float = 4.0) -> list[Servic
|
|
|
348
346
|
# Assemble dataclasses
|
|
349
347
|
results: list[ServiceInstance] = []
|
|
350
348
|
for inst in sorted(ptr_targets):
|
|
351
|
-
|
|
352
|
-
target = srv.get("target")
|
|
353
|
-
host = (target[:-1] if target and target.endswith(".") else target) or None
|
|
354
|
-
addrs = host_addrs.get(target, []) if target else []
|
|
349
|
+
srv_entries = srv_map.get(inst, [])
|
|
355
350
|
props = txt_map.get(inst, {})
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
351
|
+
for srv in srv_entries:
|
|
352
|
+
target = srv.get("target")
|
|
353
|
+
host = (target[:-1] if target and target.endswith(".") else target) or None
|
|
354
|
+
addrs = host_addrs.get(target, []) if target else []
|
|
355
|
+
results.append(
|
|
356
|
+
ServiceInstance(
|
|
357
|
+
instance=inst,
|
|
358
|
+
host=host,
|
|
359
|
+
port=srv.get("port"),
|
|
360
|
+
addresses=addrs,
|
|
361
|
+
properties=props,
|
|
362
|
+
)
|
|
363
363
|
)
|
|
364
|
-
)
|
|
365
364
|
return results
|
|
366
365
|
|
|
367
366
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from typer_injector import InjectingTyper
|
|
5
|
+
|
|
6
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep
|
|
7
|
+
from pymobiledevice3.services.mobile_activation import MobileActivationService
|
|
8
|
+
|
|
9
|
+
cli = InjectingTyper(
|
|
10
|
+
name="activation",
|
|
11
|
+
help="Perform iCloud activation/deactivation or query the current state",
|
|
12
|
+
no_args_is_help=True,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@cli.command()
|
|
17
|
+
def state(service_provider: ServiceProviderDep) -> None:
|
|
18
|
+
"""Get current activation state"""
|
|
19
|
+
print(MobileActivationService(service_provider).state)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@cli.command()
|
|
23
|
+
def activate(
|
|
24
|
+
service_provider: ServiceProviderDep,
|
|
25
|
+
now: Annotated[
|
|
26
|
+
bool,
|
|
27
|
+
typer.Option(help="do not wait for next nonce cycle"),
|
|
28
|
+
] = False,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Activate device"""
|
|
31
|
+
activation_service = MobileActivationService(service_provider)
|
|
32
|
+
if not now:
|
|
33
|
+
activation_service.wait_for_activation_session()
|
|
34
|
+
activation_service.activate()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@cli.command()
|
|
38
|
+
def deactivate(service_provider: ServiceProviderDep) -> None:
|
|
39
|
+
"""Deactivate device"""
|
|
40
|
+
MobileActivationService(service_provider).deactivate()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@cli.command()
|
|
44
|
+
def itunes(service_provider: ServiceProviderDep) -> None:
|
|
45
|
+
"""Tell the device that it has been connected to iTunes (useful for < iOS 4)"""
|
|
46
|
+
service_provider.set_value(True, key="iTunesHasConnected")
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Annotated
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from typer_injector import InjectingTyper
|
|
6
|
+
|
|
7
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep
|
|
8
|
+
from pymobiledevice3.services.afc import AfcService, AfcShell
|
|
9
|
+
|
|
10
|
+
cli = InjectingTyper(
|
|
11
|
+
name="afc",
|
|
12
|
+
help="Browse, push, and pull files via the AFC service (/var/mobile/Media).",
|
|
13
|
+
no_args_is_help=True,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@cli.command("shell")
|
|
18
|
+
def afc_shell(service_provider: ServiceProviderDep) -> None:
|
|
19
|
+
"""Open an interactive AFC shell rooted at /var/mobile/Media."""
|
|
20
|
+
AfcShell.create(service_provider)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@cli.command("pull")
|
|
24
|
+
def afc_pull(
|
|
25
|
+
service_provider: ServiceProviderDep,
|
|
26
|
+
remote_file: Path,
|
|
27
|
+
local_file: Path,
|
|
28
|
+
ignore_errors: Annotated[
|
|
29
|
+
bool,
|
|
30
|
+
typer.Option(
|
|
31
|
+
"--ignore-errors",
|
|
32
|
+
"-i",
|
|
33
|
+
help="Continue downloading even if some files error (best-effort pull).",
|
|
34
|
+
),
|
|
35
|
+
],
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Download a remote path under /var/mobile/Media to the local filesystem."""
|
|
38
|
+
AfcService(lockdown=service_provider).pull(str(remote_file), str(local_file), ignore_errors=ignore_errors)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@cli.command("push")
|
|
42
|
+
def afc_push(service_provider: ServiceProviderDep, local_file: Path, remote_file: Path) -> None:
|
|
43
|
+
"""Upload a local file into /var/mobile/Media."""
|
|
44
|
+
AfcService(lockdown=service_provider).push(str(local_file), str(remote_file))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@cli.command("ls")
|
|
48
|
+
def afc_ls(
|
|
49
|
+
service_provider: ServiceProviderDep,
|
|
50
|
+
remote_file: Path,
|
|
51
|
+
recursive: Annotated[
|
|
52
|
+
bool,
|
|
53
|
+
typer.Option("--recursive", "-r", help="Recurse into subdirectories when listing."),
|
|
54
|
+
] = False,
|
|
55
|
+
) -> None:
|
|
56
|
+
"""List files under /var/mobile/Media (optionally recursively)."""
|
|
57
|
+
for path in AfcService(lockdown=service_provider).dirlist(str(remote_file), -1 if recursive else 1):
|
|
58
|
+
print(path)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@cli.command("rm")
|
|
62
|
+
def afc_rm(service_provider: ServiceProviderDep, remote_file: Path) -> None:
|
|
63
|
+
"""Delete a file under /var/mobile/Media."""
|
|
64
|
+
AfcService(lockdown=service_provider).rm(str(remote_file))
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from typer_injector import InjectingTyper
|
|
4
|
+
|
|
5
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_json
|
|
6
|
+
from pymobiledevice3.services.amfi import AmfiService
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
cli = InjectingTyper(
|
|
12
|
+
name="amfi",
|
|
13
|
+
help="Enable developer-mode or query its state",
|
|
14
|
+
no_args_is_help=True,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@cli.command()
|
|
19
|
+
def reveal_developer_mode(service_provider: ServiceProviderDep) -> None:
|
|
20
|
+
"""reveal developer mode option in device's UI"""
|
|
21
|
+
AmfiService(service_provider).reveal_developer_mode_option_in_ui()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@cli.command()
|
|
25
|
+
def enable_developer_mode(service_provider: ServiceProviderDep) -> None:
|
|
26
|
+
"""enable developer mode"""
|
|
27
|
+
AmfiService(service_provider).enable_developer_mode()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@cli.command()
|
|
31
|
+
def developer_mode_status(service_provider: ServiceProviderDep) -> None:
|
|
32
|
+
"""query developer mode status"""
|
|
33
|
+
print_json(service_provider.developer_mode_status)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Annotated, Literal
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from typer_injector import InjectingTyper
|
|
6
|
+
|
|
7
|
+
from pymobiledevice3.cli.cli_common import ServiceProviderDep, print_json
|
|
8
|
+
from pymobiledevice3.services.house_arrest import HouseArrestService
|
|
9
|
+
from pymobiledevice3.services.installation_proxy import InstallationProxyService
|
|
10
|
+
|
|
11
|
+
cli = InjectingTyper(
|
|
12
|
+
name="apps",
|
|
13
|
+
help="List, query, install, uninstall, and inspect apps on the device.",
|
|
14
|
+
no_args_is_help=True,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@cli.command("list")
|
|
19
|
+
def apps_list(
|
|
20
|
+
service_provider: ServiceProviderDep,
|
|
21
|
+
app_type: Annotated[
|
|
22
|
+
Literal["System", "User", "Hidden", "Any"],
|
|
23
|
+
typer.Option(
|
|
24
|
+
"--type",
|
|
25
|
+
"-t",
|
|
26
|
+
help="Filter by application type (System/User/Hidden/Any).",
|
|
27
|
+
),
|
|
28
|
+
] = "Any",
|
|
29
|
+
calculate_sizes: Annotated[
|
|
30
|
+
bool,
|
|
31
|
+
typer.Option(help="Include app size information (slower)."),
|
|
32
|
+
] = False,
|
|
33
|
+
) -> None:
|
|
34
|
+
"""List installed apps."""
|
|
35
|
+
print_json(
|
|
36
|
+
InstallationProxyService(lockdown=service_provider).get_apps(
|
|
37
|
+
application_type=app_type, calculate_sizes=calculate_sizes
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@cli.command("query")
|
|
43
|
+
def apps_query(
|
|
44
|
+
service_provider: ServiceProviderDep,
|
|
45
|
+
bundle_identifiers: list[str],
|
|
46
|
+
calculate_sizes: Annotated[
|
|
47
|
+
bool,
|
|
48
|
+
typer.Option(help="Include app size information (slower)."),
|
|
49
|
+
] = False,
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Return metadata for specific bundle identifiers."""
|
|
52
|
+
print_json(
|
|
53
|
+
InstallationProxyService(lockdown=service_provider).get_apps(
|
|
54
|
+
calculate_sizes=calculate_sizes, bundle_identifiers=bundle_identifiers
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@cli.command("uninstall")
|
|
60
|
+
def uninstall(service_provider: ServiceProviderDep, bundle_id: str) -> None:
|
|
61
|
+
"""Uninstall an app by bundle identifier."""
|
|
62
|
+
InstallationProxyService(lockdown=service_provider).uninstall(bundle_id)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@cli.command("install")
|
|
66
|
+
def install(
|
|
67
|
+
service_provider: ServiceProviderDep,
|
|
68
|
+
package: Annotated[
|
|
69
|
+
Path,
|
|
70
|
+
typer.Argument(exists=True),
|
|
71
|
+
],
|
|
72
|
+
developer: Annotated[
|
|
73
|
+
bool,
|
|
74
|
+
typer.Option(help="Install developer package"),
|
|
75
|
+
] = False,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""Install a local .ipa/.app/.ipcc package."""
|
|
78
|
+
InstallationProxyService(lockdown=service_provider).install_from_local(package, developer=developer)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@cli.command("afc")
|
|
82
|
+
def afc(
|
|
83
|
+
service_provider: ServiceProviderDep, bundle_id: str, documents: Annotated[bool, typer.Option()] = False
|
|
84
|
+
) -> None:
|
|
85
|
+
"""Open an AFC shell into the app container; pass --documents for Documents-only."""
|
|
86
|
+
HouseArrestService(lockdown=service_provider, bundle_id=bundle_id, documents_only=documents).shell()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@cli.command("pull")
|
|
90
|
+
def pull(service_provider: ServiceProviderDep, bundle_id: str, remote_file: Path, local_file: Path) -> None:
|
|
91
|
+
"""Pull a file from an app container to a local path."""
|
|
92
|
+
HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).pull(str(remote_file), str(local_file))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@cli.command("push")
|
|
96
|
+
def push(service_provider: ServiceProviderDep, bundle_id: str, local_file: Path, remote_file: Path) -> None:
|
|
97
|
+
"""Push a local file into an app container."""
|
|
98
|
+
HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).push(str(local_file), str(remote_file))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@cli.command("rm")
|
|
102
|
+
def rm(service_provider: ServiceProviderDep, bundle_id: str, remote_file: Path) -> None:
|
|
103
|
+
"""Delete a file from an app container."""
|
|
104
|
+
HouseArrestService(lockdown=service_provider, bundle_id=bundle_id).rm(str(remote_file))
|