soundtouch-zonemaster 0.4.8__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.
- soundtouch_zonemaster-0.4.8/.env.example +16 -0
- soundtouch_zonemaster-0.4.8/.gitattributes +15 -0
- soundtouch_zonemaster-0.4.8/.github/actions/extract-metadata/action.yml +108 -0
- soundtouch_zonemaster-0.4.8/.github/dependabot.yml +22 -0
- soundtouch_zonemaster-0.4.8/.github/workflows/codeql.yml +39 -0
- soundtouch_zonemaster-0.4.8/.github/workflows/default_cicd_public.yml +436 -0
- soundtouch_zonemaster-0.4.8/.github/workflows/default_release_public.yml +95 -0
- soundtouch_zonemaster-0.4.8/.gitignore +197 -0
- soundtouch_zonemaster-0.4.8/CHANGELOG.md +837 -0
- soundtouch_zonemaster-0.4.8/LICENSE +21 -0
- soundtouch_zonemaster-0.4.8/Makefile +487 -0
- soundtouch_zonemaster-0.4.8/PKG-INFO +361 -0
- soundtouch_zonemaster-0.4.8/README.md +313 -0
- soundtouch_zonemaster-0.4.8/docs/notes/library-gotchas.md +90 -0
- soundtouch_zonemaster-0.4.8/docs/systemdesign/module_reference.md +261 -0
- soundtouch_zonemaster-0.4.8/keymappings.md +291 -0
- soundtouch_zonemaster-0.4.8/notebooks/Quickstart.ipynb +79 -0
- soundtouch_zonemaster-0.4.8/pyproject.toml +448 -0
- soundtouch_zonemaster-0.4.8/research/_click.py +96 -0
- soundtouch_zonemaster-0.4.8/research/_settings.py +153 -0
- soundtouch_zonemaster-0.4.8/research/analyze_capture.py +479 -0
- soundtouch_zonemaster-0.4.8/research/analyze_late_join.py +464 -0
- soundtouch_zonemaster-0.4.8/research/capture_model.py +278 -0
- soundtouch_zonemaster-0.4.8/research/capture_zone.py +674 -0
- soundtouch_zonemaster-0.4.8/research/defaultconfig.d/10-capture.toml +10 -0
- soundtouch_zonemaster-0.4.8/research/defaultconfig.d/20-golden.toml +13 -0
- soundtouch_zonemaster-0.4.8/research/defaultconfig.d/30-mpd-ab.toml +7 -0
- soundtouch_zonemaster-0.4.8/research/defaultconfig.toml +25 -0
- soundtouch_zonemaster-0.4.8/research/extract_protos.py +502 -0
- soundtouch_zonemaster-0.4.8/research/generate_pb.py +167 -0
- soundtouch_zonemaster-0.4.8/research/golden_check.py +264 -0
- soundtouch_zonemaster-0.4.8/research/mpd_seek_ab.py +374 -0
- soundtouch_zonemaster-0.4.8/research/observe_keys.py +232 -0
- soundtouch_zonemaster-0.4.8/research/proto/APConfigValues.proto +142 -0
- soundtouch_zonemaster-0.4.8/research/proto/APDashboardMsgDefinitions.proto +34 -0
- soundtouch_zonemaster-0.4.8/research/proto/APSourceParsing.proto +30 -0
- soundtouch_zonemaster-0.4.8/research/proto/AVSContext.proto +26 -0
- soundtouch_zonemaster-0.4.8/research/proto/AVSHeader.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/AirPlay2Introspect.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/AirPlay2Persistent.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/AirplayControllerMsgDefinitions.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/Album.proto +44 -0
- soundtouch_zonemaster-0.4.8/research/proto/AlbumInfo.proto +22 -0
- soundtouch_zonemaster-0.4.8/research/proto/Albums.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/AlexaSeekDirective.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/AmazonAccessTokenResponse.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/AmazonInternalPlaybackRequest.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/AmazonIntrospect.proto +61 -0
- soundtouch_zonemaster-0.4.8/research/proto/AmazonPlaybackEvent.proto +21 -0
- soundtouch_zonemaster-0.4.8/research/proto/AmazonSecret.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/AmazonTrackRating.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/AmazonTracks.proto +74 -0
- soundtouch_zonemaster-0.4.8/research/proto/Artist.proto +26 -0
- soundtouch_zonemaster-0.4.8/research/proto/ArtistInfo.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/Artists.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/ArtistsByCategory.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/AudioNotificationAccountIntrospect.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/AudioNotificationProxyPlayInfo.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/AudioNotificationServiceIntrospect.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/AudioPathControl.proto +64 -0
- soundtouch_zonemaster-0.4.8/research/proto/AudioServerMsgAudioData.proto +25 -0
- soundtouch_zonemaster-0.4.8/research/proto/AudioServerMsgDefinitions.proto +292 -0
- soundtouch_zonemaster-0.4.8/research/proto/AuthServerInfo.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/AuthenticationResponse.proto +44 -0
- soundtouch_zonemaster-0.4.8/research/proto/BTProxy.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/BatteryMonitorMsgDefinitions.proto +83 -0
- soundtouch_zonemaster-0.4.8/research/proto/BoseLinkServerMsgDefinitions.proto +384 -0
- soundtouch_zonemaster-0.4.8/research/proto/CC2540UpdateMsgDefinitions.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/CLIServerMsgDefinitions.proto +30 -0
- soundtouch_zonemaster-0.4.8/research/proto/CLIServerMsgIds.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/Charts.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/ClientConfig.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/ClockConfiguration.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/ClockSyncMsgDefinitions.proto +58 -0
- soundtouch_zonemaster-0.4.8/research/proto/ClockTime.proto +26 -0
- soundtouch_zonemaster-0.4.8/research/proto/Common.proto +68 -0
- soundtouch_zonemaster-0.4.8/research/proto/ConfigResponse.proto +27 -0
- soundtouch_zonemaster-0.4.8/research/proto/Configuration/BoseAppCfg.proto +80 -0
- soundtouch_zonemaster-0.4.8/research/proto/Configuration/SoundTouchSdkPrivateCfg.proto +23 -0
- soundtouch_zonemaster-0.4.8/research/proto/Countries.proto +17 -0
- soundtouch_zonemaster-0.4.8/research/proto/Country.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/CustomRadioGetTracks.proto +27 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerContentType.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerError.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerInternalPlaybackRequest.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerIntrospect.proto +21 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerLocation.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerLoginResponse.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerPersistent.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerQueuedTrack.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/DeezerTrackInfo.proto +25 -0
- soundtouch_zonemaster-0.4.8/research/proto/EnterCodeResponse.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/EnvDefine.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/EnvList.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/EnvSwitch.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/ExtSourceMsgDefinitions.proto +110 -0
- soundtouch_zonemaster-0.4.8/research/proto/ExternalMediaPlayerAvsApi.proto +153 -0
- soundtouch_zonemaster-0.4.8/research/proto/Favorites.proto +38 -0
- soundtouch_zonemaster-0.4.8/research/proto/ForYou.proto +36 -0
- soundtouch_zonemaster-0.4.8/research/proto/FullAccount.proto +22 -0
- soundtouch_zonemaster-0.4.8/research/proto/GenreList.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/GetCodeResponse.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/Hpdt.proto +76 -0
- soundtouch_zonemaster-0.4.8/research/proto/IHeartCILocation.proto +36 -0
- soundtouch_zonemaster-0.4.8/research/proto/IHeartContentType.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/IHeartError.proto +36 -0
- soundtouch_zonemaster-0.4.8/research/proto/IHeartIntrospect.proto +41 -0
- soundtouch_zonemaster-0.4.8/research/proto/IHeartLoginResponse.proto +19 -0
- soundtouch_zonemaster-0.4.8/research/proto/IHeartQueuedTrack.proto +31 -0
- soundtouch_zonemaster-0.4.8/research/proto/IPCMessageEnvelopeBase.proto +19 -0
- soundtouch_zonemaster-0.4.8/research/proto/IPCProtocolDefinitions.proto +27 -0
- soundtouch_zonemaster-0.4.8/research/proto/IpcServices.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/ListenHistory.proto +60 -0
- soundtouch_zonemaster-0.4.8/research/proto/LiveRadioMetaData.proto +30 -0
- soundtouch_zonemaster-0.4.8/research/proto/LiveRadioRecommendations.proto +17 -0
- soundtouch_zonemaster-0.4.8/research/proto/LiveRadioRegister.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/LiveRadioTemplates.proto +22 -0
- soundtouch_zonemaster-0.4.8/research/proto/LiveStations.proto +28 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicAlbumInfo.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicArtistInfo.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicAuthorInfo.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicError.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicInternalPlaybackRequest.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicIntrospect.proto +21 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicPodcastInfo.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicQueuedTrack.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicTrackInfo.proto +38 -0
- soundtouch_zonemaster-0.4.8/research/proto/LocalMusicTracks.proto +29 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeAddDevice.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeAddDeviceResponse.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeAddPresetRequest.proto +17 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeAddRecentRequest.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeClientIntrospect.proto +23 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeConfiguration.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeDevice.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeDeviceData.proto +55 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeDevices.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeGroup.proto +23 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargePreset.proto +19 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargePresets.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeRecent.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeRecents.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeSource.proto +24 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeSourceProviders.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeSourceSettings.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeSources.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/MargeStatus.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/Market.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/MarketList.proto +20 -0
- soundtouch_zonemaster-0.4.8/research/proto/NetManager.proto +193 -0
- soundtouch_zonemaster-0.4.8/research/proto/NowPlayingSupplement.proto +22 -0
- soundtouch_zonemaster-0.4.8/research/proto/OAuthAccessToken.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/OAuthTokens.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/OAuthUserInfo.proto +29 -0
- soundtouch_zonemaster-0.4.8/research/proto/OnDemandEpisodesResponse.proto +21 -0
- soundtouch_zonemaster-0.4.8/research/proto/OnDemandMetadata.proto +127 -0
- soundtouch_zonemaster-0.4.8/research/proto/PerfectFor.proto +42 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/AirplayConfiguration.proto +89 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/ExtSource.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/Lightswitch.proto +25 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/Pandora.proto +36 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/SourceInfo.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/SourceRegistry.proto +23 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/StatsDataCapture.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/SystemConfiguration.proto +29 -0
- soundtouch_zonemaster-0.4.8/research/proto/Persistence/UPnP.proto +20 -0
- soundtouch_zonemaster-0.4.8/research/proto/PresetResponse.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/PresetUpdate.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/ProtoToMarkup/MarkupOptions.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/ProviderSettings.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/RalphError.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/RegisterClientResponse.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/ReportStreamResponse.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/SCMHardwareNVRamConfigFileFmt.proto +38 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSAsyncError.proto +21 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSAudioError.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSAudioReason.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSAudioSetURL.proto +27 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSAudioState.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSAudioStatus.proto +22 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSAuthServerInfo.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSAvailability.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSConnectionStatus.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSContentItem.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSContentItemHistory.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSCreateAccount.proto +24 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSCreateAccountProxy.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSDeactivate.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSDeployment.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSDeviceInfo.proto +32 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSDeviceStatus.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSErrorSeverity.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSFilterType.proto +17 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSFlexUI.proto +27 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSGroupStatus.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSIntrospect.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSItemType.proto +37 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSItems.proto +36 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSLogAutomation.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSMenuType.proto +34 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSMsgDefinitions.proto +90 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSMute.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSNavigate.proto +26 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSNetworkStatus.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSNowPlaying.proto +71 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSOAuthCredentials.proto +20 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSPlayQueueIntrospect.proto +22 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSPlayStatus.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSPlaybackRequest.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSProtocolVersion.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSRating.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSRecreateAccount.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSRegisterService.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSRemoveAccount.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSRepeatMode.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSSDPDiscoveryService.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSSDPDiscoveryStatus.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSearch.proto +24 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSections.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSeekRelative.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSeekToTime.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSServiceAndAccountSettings.proto +67 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSServiceInfo.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSShuffleMode.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSkipList.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSortOrder.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSourceDeselect.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSSourceSelect.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSStationInfo.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSStatus.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSStreamType.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSStreamingQuality.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSUpdateSecret.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSVoid.proto +6 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSVolumeControl.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSVolumeStatus.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSZeroconfRegisterService.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSZeroconfTxtRecord.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSZeroconfUnregisterService.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/STSZoneStatus.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/SWUpdateUrl.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/ScmmondClient.proto +37 -0
- soundtouch_zonemaster-0.4.8/research/proto/ShelbyKeys.proto +66 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoftwareUpdate/SwUpdateCheck.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoftwareUpdateAPIMsgDefinitions.proto +29 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoftwareUpdateIndex/SoftwareUpdateIndex.proto +70 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchAccountId.proto +5 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/AcctMode.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/AcctModeType.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/AudioService.proto +27 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/ContentItem.proto +42 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/ContentItemList.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/ContentSelectionService.proto +45 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/ErrorType.proto +345 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/ErrorUpdate.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/GetActiveWirelessProfile.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/Group.proto +49 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/Msg.proto +43 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/NetworkService.proto +62 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/PlayerService.proto +210 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/Presets.proto +17 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/Recents.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/SSDPDiscoveryUpdate.proto +17 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/STSSettings.proto +56 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/ServiceSettings.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/Setup.proto +39 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/SoftwareUpdateService.proto +42 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/SoundTouchSdkInfo.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/Status.proto +60 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/SystemService.proto +124 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/Updates.proto +126 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/Zone.proto +25 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/initializationcompleteaction.proto +21 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/userActivityUpdate.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchInterface/userInactivityUpdate.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/SoundTouchSdkAPI.proto +24 -0
- soundtouch_zonemaster-0.4.8/research/proto/SpotifyImages.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/SpotifyInternalPlaybackRequest.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/SpotifyIntrospect.proto +43 -0
- soundtouch_zonemaster-0.4.8/research/proto/SpotifyLocation.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/SpotifyPersistent.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/SpotifyPreset.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/SpotifyTracks.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/SpotifyUserSavedTracks.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/Startup.proto +42 -0
- soundtouch_zonemaster-0.4.8/research/proto/StateList.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/Station.proto +28 -0
- soundtouch_zonemaster-0.4.8/research/proto/StationDetails.proto +31 -0
- soundtouch_zonemaster-0.4.8/research/proto/StationType.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/StreamSources/StationTracks.proto +63 -0
- soundtouch_zonemaster-0.4.8/research/proto/StreamUrl.proto +24 -0
- soundtouch_zonemaster-0.4.8/research/proto/Streams.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/SxmIntrospect.proto +38 -0
- soundtouch_zonemaster-0.4.8/research/proto/SxmRegistrationInfo.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/TPDAEndpoint.proto +19 -0
- soundtouch_zonemaster-0.4.8/research/proto/TPDAHeader.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/TPDAPlaybackStateReporter.proto +133 -0
- soundtouch_zonemaster-0.4.8/research/proto/Talk.proto +60 -0
- soundtouch_zonemaster-0.4.8/research/proto/ThumbResponse.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/TokenResponse.proto +25 -0
- soundtouch_zonemaster-0.4.8/research/proto/Track.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/TrackBundle.proto +19 -0
- soundtouch_zonemaster-0.4.8/research/proto/TrackEvents.proto +25 -0
- soundtouch_zonemaster-0.4.8/research/proto/Tracks.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/UpdateGroup.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/UpnpIntrospect.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/UserBatch.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/UserInfo.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/UserOptions.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/UserProfile.proto +16 -0
- soundtouch_zonemaster-0.4.8/research/proto/UserSubscription.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/BCOReset.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Balance.proto +23 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Bass.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/BassCapabilities.proto +29 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/BearerToken.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Capabilities.proto +58 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/ClockDisplay.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/ControllerUI.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Credentials.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/GenreStationsResult.proto +26 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/GroupUIStatusNotification.proto +6 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/GroupVersion.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Info.proto +30 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Introspect.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Item.proto +74 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/KeyData.proto +60 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/MarconiUI.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/MasterMessage.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Mono.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Navigate.proto +79 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/NetStats.proto +63 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/OAuthCredentials.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/OledUI.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/PairDeviceWithAccount.proto +17 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/PerformWirelessSiteSurvey.proto +34 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/PingRequest.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/PlayInfo.proto +15 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/PlaySound.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/PlaybackRequest.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Power.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/PowerManagementResponse.proto +44 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Results.proto +30 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/SSDPDiscoveryStatus.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/SWUpdateCheckResponse.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/SWUpdateQueryResponse.proto +28 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/Search.proto +54 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/SearchSortOrder.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/ServiceAvailability.proto +18 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/SlaveMessage.proto +12 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/SourceIcon.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/StationInfo.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/SupportedUrls.proto +11 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/TrackInfo.proto +8 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/VersionInfo.proto +35 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/WirelessProfile.proto +37 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebInterface/ZoneList.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebServerCfg.proto +9 -0
- soundtouch_zonemaster-0.4.8/research/proto/WebServerMsgDefinitions.proto +14 -0
- soundtouch_zonemaster-0.4.8/research/proto/ZeroconfRegisterService.proto +10 -0
- soundtouch_zonemaster-0.4.8/research/proto/ZeroconfTxtRecord.proto +6 -0
- soundtouch_zonemaster-0.4.8/research/proto/ZeroconfUnregisterService.proto +7 -0
- soundtouch_zonemaster-0.4.8/research/proto/ZoneState.proto +13 -0
- soundtouch_zonemaster-0.4.8/research/sync_report.py +265 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/__init__.py +13 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/__init__conf__.py +99 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/__main__.py +14 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/__init__.py +5 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/aftertouch/__init__.py +10 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/aftertouch/registry.py +144 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/__init__.py +5 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/boundary.py +313 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/context.py +49 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/envelope.py +116 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/main.py +77 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/prototype.py +371 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/py.typed +0 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/safe_console.py +218 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/service/__init__.py +14 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/service/config_cmd.py +84 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/service/deploy_cmd.py +76 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/service/root.py +226 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/cli/typed_click.py +95 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/__init__.py +20 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/10-zone.toml +33 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/20-files.toml +46 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/30-registry.toml +31 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/40-membership.toml +35 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/50-dialling.toml +47 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/60-switch.toml +17 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/70-observer.toml +34 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/80-prototype.toml +31 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.d/90-mpd.toml +48 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/defaultconfig.toml +47 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/deploy.py +58 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/display.py +113 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/errors.py +26 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/loader.py +154 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/overrides.py +103 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/config/settings_map.py +182 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/files/__init__.py +5 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/files/atomicfile.py +63 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/files/channel_file.py +164 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/files/state_file.py +145 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/files/switch_file.py +77 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/logging/__init__.py +5 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/logging/narration.py +43 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/mpd/__init__.py +23 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/mpd/client.py +292 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/py.typed +0 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/__init__.py +9 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/clock.py +199 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/connections.py +529 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/http_api.py +332 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/ipc.py +175 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/observer.py +200 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/AudioServerMsgAudioData_pb2.py +40 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/AudioServerMsgAudioData_pb2.pyi +48 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/AudioServerMsgDefinitions_pb2.py +133 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/AudioServerMsgDefinitions_pb2.pyi +490 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/IPCMessageEnvelopeBase_pb2.py +40 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/IPCMessageEnvelopeBase_pb2.pyi +36 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/ProtoToMarkup/MarkupOptions_pb2.py +35 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/ProtoToMarkup/MarkupOptions_pb2.pyi +17 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/ProtoToMarkup/__init__.py +0 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/SoundTouchInterface/Zone_pb2.py +41 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/SoundTouchInterface/Zone_pb2.pyi +42 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/SoundTouchInterface/__init__.py +0 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/pb/__init__.py +25 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/placement.py +382 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/reports.py +70 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/source.py +380 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/speaker_http.py +156 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/wire.py +29 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/xmlmodels.py +155 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/xmlread.py +156 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/adapters/soundtouch/zone_master.py +628 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/__init__.py +5 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/errors.py +60 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/options.py +228 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/outcome.py +75 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/ports.py +420 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/prototype.py +114 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/py.typed +0 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/__init__.py +16 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/channels.py +166 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/constants.py +105 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/dialling.py +519 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/keys.py +205 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/service.py +104 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/speakers.py +150 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/state.py +357 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/volume.py +363 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/application/zone_service/zone.py +705 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/composition/__init__.py +135 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/composition/py.typed +0 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/__init__.py +5 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/calibration.py +291 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/channellist.py +407 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/dialling.py +214 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/enums.py +266 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/events.py +83 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/frames.py +211 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/housevolume.py +110 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/logfn.py +28 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/longpress.py +194 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/membership.py +233 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/mpd.py +58 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/playorder.py +112 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/presses.py +392 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/py.typed +0 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/speakers.py +82 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/state.py +145 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/station.py +75 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/switch.py +18 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/timeline.py +185 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/xmlfmt.py +90 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/domain/zonexml.py +137 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/entry.py +34 -0
- soundtouch_zonemaster-0.4.8/src/soundtouch_zonemaster/py.typed +0 -0
- soundtouch_zonemaster-0.4.8/tests/conftest.py +145 -0
- soundtouch_zonemaster-0.4.8/tests/e2e/speaker_probe.py +63 -0
- soundtouch_zonemaster-0.4.8/tests/e2e_config.py +111 -0
- soundtouch_zonemaster-0.4.8/tests/e2e_defaults.toml +20 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/aftertouch-devices.json +54 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/burst-as-a-slave-frames.json +190 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/golden/channel_file.json +2920 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/golden/dialler.json +989 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/golden/observer.json +12505 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/golden/options.json +2815 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/golden/registry.json +503 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/golden/seeding.json +535 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/golden/slavemsg.json +1368 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/golden/state_file.json +936 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/house-20260921-dialling-frames.json +859 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/live-run-2-frames.json +1560 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/live-run-frames.json +760 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/notification-nowplaying.txt +5 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/notification-volume.txt +4 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/slavemsg-keydata.txt +10 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/superfly-24k.aac +0 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/sync-run.log +25 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/sync-silent.log +14 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/sync-spread.log +12 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/technikumcity-24k.mp3 +0 -0
- soundtouch_zonemaster-0.4.8/tests/fixtures/zone_frames.json +127 -0
- soundtouch_zonemaster-0.4.8/tests/hang_watchdog.py +254 -0
- soundtouch_zonemaster-0.4.8/tests/mpdfake.py +177 -0
- soundtouch_zonemaster-0.4.8/tests/registry_double.py +97 -0
- soundtouch_zonemaster-0.4.8/tests/speaker_double.py +540 -0
- soundtouch_zonemaster-0.4.8/tests/test_boundary_golden.py +1441 -0
- soundtouch_zonemaster-0.4.8/tests/test_calibration.py +245 -0
- soundtouch_zonemaster-0.4.8/tests/test_capture_model.py +100 -0
- soundtouch_zonemaster-0.4.8/tests/test_capture_zone.py +191 -0
- soundtouch_zonemaster-0.4.8/tests/test_channel_file.py +292 -0
- soundtouch_zonemaster-0.4.8/tests/test_channellist.py +389 -0
- soundtouch_zonemaster-0.4.8/tests/test_click_facades.py +103 -0
- soundtouch_zonemaster-0.4.8/tests/test_config.py +327 -0
- soundtouch_zonemaster-0.4.8/tests/test_config_private_overrides.py +155 -0
- soundtouch_zonemaster-0.4.8/tests/test_dialling.py +312 -0
- soundtouch_zonemaster-0.4.8/tests/test_domain_is_pure.py +129 -0
- soundtouch_zonemaster-0.4.8/tests/test_doubles.py +58 -0
- soundtouch_zonemaster-0.4.8/tests/test_e2e_config.py +96 -0
- soundtouch_zonemaster-0.4.8/tests/test_e2e_speakers.py +167 -0
- soundtouch_zonemaster-0.4.8/tests/test_export_public.py +509 -0
- soundtouch_zonemaster-0.4.8/tests/test_extract_protos.py +257 -0
- soundtouch_zonemaster-0.4.8/tests/test_golden_check.py +56 -0
- soundtouch_zonemaster-0.4.8/tests/test_house_dialling.py +215 -0
- soundtouch_zonemaster-0.4.8/tests/test_housevolume.py +127 -0
- soundtouch_zonemaster-0.4.8/tests/test_install_service.py +189 -0
- soundtouch_zonemaster-0.4.8/tests/test_key_events.py +145 -0
- soundtouch_zonemaster-0.4.8/tests/test_longpress.py +336 -0
- soundtouch_zonemaster-0.4.8/tests/test_membership.py +441 -0
- soundtouch_zonemaster-0.4.8/tests/test_metadata.py +85 -0
- soundtouch_zonemaster-0.4.8/tests/test_metadata_sync.py +86 -0
- soundtouch_zonemaster-0.4.8/tests/test_module_entry.py +126 -0
- soundtouch_zonemaster-0.4.8/tests/test_mpd_seek_ab.py +77 -0
- soundtouch_zonemaster-0.4.8/tests/test_mpd_status.py +59 -0
- soundtouch_zonemaster-0.4.8/tests/test_mpdclient.py +595 -0
- soundtouch_zonemaster-0.4.8/tests/test_never_touch.py +171 -0
- soundtouch_zonemaster-0.4.8/tests/test_no_private_names.py +91 -0
- soundtouch_zonemaster-0.4.8/tests/test_observe_keys.py +82 -0
- soundtouch_zonemaster-0.4.8/tests/test_observer.py +335 -0
- soundtouch_zonemaster-0.4.8/tests/test_play_order.py +160 -0
- soundtouch_zonemaster-0.4.8/tests/test_ports.py +64 -0
- soundtouch_zonemaster-0.4.8/tests/test_press_or_echo.py +690 -0
- soundtouch_zonemaster-0.4.8/tests/test_registry.py +178 -0
- soundtouch_zonemaster-0.4.8/tests/test_research_config.py +106 -0
- soundtouch_zonemaster-0.4.8/tests/test_safe_console.py +172 -0
- soundtouch_zonemaster-0.4.8/tests/test_service_cli.py +274 -0
- soundtouch_zonemaster-0.4.8/tests/test_service_config.py +627 -0
- soundtouch_zonemaster-0.4.8/tests/test_service_loopback.py +4014 -0
- soundtouch_zonemaster-0.4.8/tests/test_shutdown_is_quiet.py +170 -0
- soundtouch_zonemaster-0.4.8/tests/test_stream_end.py +132 -0
- soundtouch_zonemaster-0.4.8/tests/test_switch_and_state.py +404 -0
- soundtouch_zonemaster-0.4.8/tests/test_sync_report.py +211 -0
- soundtouch_zonemaster-0.4.8/tests/test_usage_error_envelope.py +127 -0
- soundtouch_zonemaster-0.4.8/tests/test_wheel_contents.py +95 -0
- soundtouch_zonemaster-0.4.8/tests/test_xmlread.py +289 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_bind_retry.py +176 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_cli.py +118 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_cli_machine_mode.py +160 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_frames.py +172 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_http_api.py +136 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_ipc.py +138 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_join_plan.py +347 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_limits.py +296 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_local_e2e.py +1066 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_reports.py +23 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_run_loop.py +191 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_select.py +47 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_source_resolution.py +111 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_speaker_calls.py +302 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_timeline.py +106 -0
- soundtouch_zonemaster-0.4.8/tests/test_zonemaster_xml_escaping.py +242 -0
- soundtouch_zonemaster-0.4.8/tools/_click.py +91 -0
- soundtouch_zonemaster-0.4.8/tools/export_public.py +591 -0
- soundtouch_zonemaster-0.4.8/tools/install_service.py +229 -0
- soundtouch_zonemaster-0.4.8/tools/public_redactions.example.txt +27 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Optional. The hardware tests read their settings from tests/e2e_defaults.d/90-e2e-rnhome.toml
|
|
2
|
+
# (copy tests/e2e_defaults.d/90-e2e-rnhome.toml.example), which is where they belong: typed, and
|
|
3
|
+
# beside the safe defaults they override. A .env at the repository root (gitignored) is still read
|
|
4
|
+
# ABOVE that file, so a key set here wins over it. Everything in a .env is text: the speakers comma
|
|
5
|
+
# separated, E2E_AUDIBLE a word. Placeholders only below.
|
|
6
|
+
|
|
7
|
+
# The host on the speaker LAN that the probe runs on, and how to reach it.
|
|
8
|
+
E2E_HOST=
|
|
9
|
+
E2E_USER=root
|
|
10
|
+
E2E_KEY=/path/to/ssh/key
|
|
11
|
+
|
|
12
|
+
# The speakers the read-only probe may query, comma separated. List every box in the house.
|
|
13
|
+
E2E_SPEAKERS=192.0.2.11,192.0.2.12
|
|
14
|
+
|
|
15
|
+
# Whether a test may do something AUDIBLE. Leave false unless you know who is at home.
|
|
16
|
+
E2E_AUDIBLE=false
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Normalize every text file to LF in the repo AND the working tree, on every OS.
|
|
2
|
+
# `text=auto` auto-detects binary and leaves it untouched; `eol=lf` forces LF checkout
|
|
3
|
+
# so a Windows edit/save cannot reintroduce CRLF churn.
|
|
4
|
+
* text=auto eol=lf
|
|
5
|
+
|
|
6
|
+
# Runtime-critical: CRLF here breaks execution on Linux (^M in shebang / make recipes).
|
|
7
|
+
Makefile text eol=lf
|
|
8
|
+
*.sh text eol=lf
|
|
9
|
+
*.py text eol=lf
|
|
10
|
+
*.ps1 text eol=lf
|
|
11
|
+
*.toml text eol=lf
|
|
12
|
+
*.md text eol=lf
|
|
13
|
+
*.json text eol=lf
|
|
14
|
+
*.yml text eol=lf
|
|
15
|
+
*.yaml text eol=lf
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
name: Extract project metadata
|
|
2
|
+
description: >-
|
|
3
|
+
Parse pyproject.toml and expose project metadata as step outputs.
|
|
4
|
+
Requires Python to be available in the runner environment.
|
|
5
|
+
Auto-installs rtoml if not already present.
|
|
6
|
+
|
|
7
|
+
outputs:
|
|
8
|
+
PACKAGE_MODULE:
|
|
9
|
+
description: Python-importable module name (underscored)
|
|
10
|
+
value: ${{ steps.meta.outputs.PACKAGE_MODULE }}
|
|
11
|
+
PROJECT_NAME:
|
|
12
|
+
description: Project name from pyproject.toml
|
|
13
|
+
value: ${{ steps.meta.outputs.PROJECT_NAME }}
|
|
14
|
+
CLI_BIN:
|
|
15
|
+
description: CLI entry-point binary name
|
|
16
|
+
value: ${{ steps.meta.outputs.CLI_BIN }}
|
|
17
|
+
SRC_PATH:
|
|
18
|
+
description: Source directory path (e.g. "src")
|
|
19
|
+
value: ${{ steps.meta.outputs.SRC_PATH }}
|
|
20
|
+
COV_FAIL_UNDER:
|
|
21
|
+
description: Minimum coverage percentage from tool.coverage.report.fail_under
|
|
22
|
+
value: ${{ steps.meta.outputs.COV_FAIL_UNDER }}
|
|
23
|
+
COV_REPORT_FILE:
|
|
24
|
+
description: Coverage report filename (e.g. "coverage.xml")
|
|
25
|
+
value: ${{ steps.meta.outputs.COV_REPORT_FILE }}
|
|
26
|
+
PYTEST_VERBOSITY:
|
|
27
|
+
description: Pytest verbosity flag (e.g. "-vv")
|
|
28
|
+
value: ${{ steps.meta.outputs.PYTEST_VERBOSITY }}
|
|
29
|
+
BANDIT_SKIP_FLAG:
|
|
30
|
+
description: Bandit skip flag string (e.g. "-s B101,B601") or empty
|
|
31
|
+
value: ${{ steps.meta.outputs.BANDIT_SKIP_FLAG }}
|
|
32
|
+
PYTEST_MARKER_EXPR:
|
|
33
|
+
description: >-
|
|
34
|
+
Marker expression for the CI test run (e.g. "not local_only and not integration"),
|
|
35
|
+
built from tool.ci.pytest-exclude-markers
|
|
36
|
+
value: ${{ steps.meta.outputs.PYTEST_MARKER_EXPR }}
|
|
37
|
+
|
|
38
|
+
runs:
|
|
39
|
+
using: composite
|
|
40
|
+
steps:
|
|
41
|
+
- name: Extract project metadata from pyproject.toml
|
|
42
|
+
id: meta
|
|
43
|
+
shell: python
|
|
44
|
+
run: |
|
|
45
|
+
import os, subprocess, sys
|
|
46
|
+
try:
|
|
47
|
+
import rtoml
|
|
48
|
+
except ModuleNotFoundError:
|
|
49
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "rtoml", "-q"])
|
|
50
|
+
import rtoml
|
|
51
|
+
|
|
52
|
+
from pathlib import Path
|
|
53
|
+
data = rtoml.load(Path('pyproject.toml'))
|
|
54
|
+
|
|
55
|
+
# --- [project] section ---
|
|
56
|
+
project = data['project']['name']
|
|
57
|
+
module = project.replace('-', '_')
|
|
58
|
+
dash = project.replace('_', '-')
|
|
59
|
+
scripts = list(data['project'].get('scripts', {}).keys())
|
|
60
|
+
cli_bin = scripts[0] if scripts else dash
|
|
61
|
+
|
|
62
|
+
# --- [tool.scripts.test] section ---
|
|
63
|
+
scripts_test = data.get('tool', {}).get('scripts', {}).get('test', {})
|
|
64
|
+
src_path = scripts_test.get('src-path', 'src')
|
|
65
|
+
pytest_verbosity = scripts_test.get('pytest-verbosity', '-vv')
|
|
66
|
+
cov_report_file = scripts_test.get('coverage-report-file', 'coverage.xml')
|
|
67
|
+
|
|
68
|
+
# --- [tool.coverage.report] section ---
|
|
69
|
+
cov_fail_under = (
|
|
70
|
+
data.get('tool', {}).get('coverage', {}).get('report', {}).get('fail_under', 90)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# --- [tool.bandit] section ---
|
|
74
|
+
bandit_skips = data.get('tool', {}).get('bandit', {}).get('skips', [])
|
|
75
|
+
bandit_skip_flag = f"-s {','.join(bandit_skips)}" if bandit_skips else ""
|
|
76
|
+
|
|
77
|
+
# --- [tool.ci] section ---
|
|
78
|
+
# CI always skips local_only (those tests need a dev box). A project whose
|
|
79
|
+
# suite also carries markers CI cannot satisfy - integration tests needing a
|
|
80
|
+
# container that a separate workflow starts - names them here, rather than
|
|
81
|
+
# every such repo forking this workflow to edit one -m expression.
|
|
82
|
+
ci_config = data.get('tool', {}).get('ci', {})
|
|
83
|
+
exclude_markers = ['local_only', *ci_config.get('pytest-exclude-markers', [])]
|
|
84
|
+
pytest_marker_expr = ' and '.join(f'not {m}' for m in exclude_markers)
|
|
85
|
+
|
|
86
|
+
# Write to GITHUB_OUTPUT for composite action outputs
|
|
87
|
+
with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf-8') as out:
|
|
88
|
+
out.write(f"PROJECT_NAME={project}\n")
|
|
89
|
+
out.write(f"PACKAGE_MODULE={module}\n")
|
|
90
|
+
out.write(f"CLI_BIN={cli_bin}\n")
|
|
91
|
+
out.write(f"SRC_PATH={src_path}\n")
|
|
92
|
+
out.write(f"PYTEST_VERBOSITY={pytest_verbosity}\n")
|
|
93
|
+
out.write(f"COV_REPORT_FILE={cov_report_file}\n")
|
|
94
|
+
out.write(f"COV_FAIL_UNDER={cov_fail_under}\n")
|
|
95
|
+
out.write(f"BANDIT_SKIP_FLAG={bandit_skip_flag}\n")
|
|
96
|
+
out.write(f"PYTEST_MARKER_EXPR={pytest_marker_expr}\n")
|
|
97
|
+
|
|
98
|
+
# Also write to GITHUB_ENV so subsequent steps can use ${{ env.VAR }}
|
|
99
|
+
with open(os.environ['GITHUB_ENV'], 'a', encoding='utf-8') as env:
|
|
100
|
+
env.write(f"PROJECT_NAME={project}\n")
|
|
101
|
+
env.write(f"PACKAGE_MODULE={module}\n")
|
|
102
|
+
env.write(f"CLI_BIN={cli_bin}\n")
|
|
103
|
+
env.write(f"SRC_PATH={src_path}\n")
|
|
104
|
+
env.write(f"PYTEST_VERBOSITY={pytest_verbosity}\n")
|
|
105
|
+
env.write(f"COV_REPORT_FILE={cov_report_file}\n")
|
|
106
|
+
env.write(f"COV_FAIL_UNDER={cov_fail_under}\n")
|
|
107
|
+
env.write(f"BANDIT_SKIP_FLAG={bandit_skip_flag}\n")
|
|
108
|
+
env.write(f"PYTEST_MARKER_EXPR={pytest_marker_expr}\n")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "pip"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
allow:
|
|
8
|
+
- dependency-type: "direct"
|
|
9
|
+
labels:
|
|
10
|
+
- "dependencies"
|
|
11
|
+
commit-message:
|
|
12
|
+
prefix: "deps"
|
|
13
|
+
include: "scope"
|
|
14
|
+
- package-ecosystem: "github-actions"
|
|
15
|
+
directory: "/"
|
|
16
|
+
schedule:
|
|
17
|
+
interval: "weekly"
|
|
18
|
+
labels:
|
|
19
|
+
- "dependencies"
|
|
20
|
+
commit-message:
|
|
21
|
+
prefix: "deps"
|
|
22
|
+
include: "scope"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main, master ]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '0 8 * * 1'
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
analyze:
|
|
13
|
+
name: CodeQL Analyze
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
actions: read
|
|
17
|
+
contents: read
|
|
18
|
+
security-events: write
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
language: [ 'python' ]
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout repository
|
|
26
|
+
uses: actions/checkout@v7
|
|
27
|
+
|
|
28
|
+
- name: Initialize CodeQL
|
|
29
|
+
uses: github/codeql-action/init@v4
|
|
30
|
+
with:
|
|
31
|
+
languages: ${{ matrix.language }}
|
|
32
|
+
|
|
33
|
+
- name: Autobuild
|
|
34
|
+
uses: github/codeql-action/autobuild@v4
|
|
35
|
+
|
|
36
|
+
- name: Perform CodeQL Analysis
|
|
37
|
+
uses: github/codeql-action/analyze@v4
|
|
38
|
+
with:
|
|
39
|
+
category: "/language:${{ matrix.language }}"
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main, master ]
|
|
8
|
+
schedule:
|
|
9
|
+
# Run daily at 3:17 AM UTC (off-peak hours, odd minute to avoid congestion)
|
|
10
|
+
- cron: '17 3 * * *'
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
setup:
|
|
14
|
+
name: Extract Python versions and OS matrix from pyproject.toml
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
outputs:
|
|
17
|
+
python-versions: ${{ steps.metadata.outputs.python-versions }}
|
|
18
|
+
python-latest: ${{ steps.metadata.outputs.python-latest }}
|
|
19
|
+
os-matrix: ${{ steps.metadata.outputs.os-matrix }}
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v7
|
|
22
|
+
- uses: actions/setup-python@v7
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.x"
|
|
25
|
+
- name: Parse pyproject.toml for Python versions and OS matrix
|
|
26
|
+
id: metadata
|
|
27
|
+
shell: python
|
|
28
|
+
run: |
|
|
29
|
+
import json, os, tomllib
|
|
30
|
+
|
|
31
|
+
with open("pyproject.toml", "rb") as f:
|
|
32
|
+
data = tomllib.load(f)
|
|
33
|
+
|
|
34
|
+
# Python versions from classifiers
|
|
35
|
+
classifiers = data.get("project", {}).get("classifiers", [])
|
|
36
|
+
prefix = "Programming Language :: Python :: "
|
|
37
|
+
versions = [
|
|
38
|
+
c[len(prefix):]
|
|
39
|
+
for c in classifiers
|
|
40
|
+
if c.startswith(prefix) and "." in c[len(prefix):]
|
|
41
|
+
]
|
|
42
|
+
if not versions:
|
|
43
|
+
raise SystemExit("No Python X.Y versions found in classifiers")
|
|
44
|
+
|
|
45
|
+
# OS matrix from [tool.ci]
|
|
46
|
+
ci_config = data.get("tool", {}).get("ci", {})
|
|
47
|
+
os_list = ci_config.get("os", ["ubuntu-latest"])
|
|
48
|
+
|
|
49
|
+
with open(os.environ["GITHUB_OUTPUT"], "a") as fh:
|
|
50
|
+
fh.write(f"python-versions={json.dumps(versions)}\n")
|
|
51
|
+
fh.write(f"python-latest={versions[-1]}\n")
|
|
52
|
+
fh.write(f"os-matrix={json.dumps(os_list)}\n")
|
|
53
|
+
|
|
54
|
+
test:
|
|
55
|
+
name: Tests (Python ${{ matrix.python }}, ${{ matrix.os }})
|
|
56
|
+
needs: setup
|
|
57
|
+
runs-on: ${{ matrix.os }}
|
|
58
|
+
strategy:
|
|
59
|
+
fail-fast: false
|
|
60
|
+
matrix:
|
|
61
|
+
os: ${{ fromJSON(needs.setup.outputs.os-matrix) }}
|
|
62
|
+
python: ${{ fromJSON(needs.setup.outputs.python-versions) }}
|
|
63
|
+
env:
|
|
64
|
+
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: "1"
|
|
65
|
+
PYTHONIOENCODING: "utf-8"
|
|
66
|
+
UV_LINK_MODE: "copy"
|
|
67
|
+
UV_BREAK_SYSTEM_PACKAGES: "1"
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v7
|
|
70
|
+
- uses: actions/setup-python@v7
|
|
71
|
+
with:
|
|
72
|
+
python-version: ${{ matrix.python }}
|
|
73
|
+
- name: Install uv
|
|
74
|
+
uses: astral-sh/setup-uv@v7
|
|
75
|
+
with:
|
|
76
|
+
enable-cache: true
|
|
77
|
+
prune-cache: false
|
|
78
|
+
|
|
79
|
+
- name: Install bash 4+ on macOS
|
|
80
|
+
if: runner.os == 'macOS'
|
|
81
|
+
run: |
|
|
82
|
+
brew install bash
|
|
83
|
+
echo "$(brew --prefix)/bin" >> "$GITHUB_PATH"
|
|
84
|
+
|
|
85
|
+
- name: Extract project metadata
|
|
86
|
+
id: metadata
|
|
87
|
+
uses: ./.github/actions/extract-metadata
|
|
88
|
+
|
|
89
|
+
- name: Install CI system dependencies (Ubuntu)
|
|
90
|
+
if: runner.os == 'Linux'
|
|
91
|
+
shell: python
|
|
92
|
+
run: |
|
|
93
|
+
import subprocess
|
|
94
|
+
try:
|
|
95
|
+
import tomllib
|
|
96
|
+
except ModuleNotFoundError:
|
|
97
|
+
import pip._vendor.tomli as tomllib
|
|
98
|
+
with open("pyproject.toml", "rb") as f:
|
|
99
|
+
data = tomllib.load(f)
|
|
100
|
+
deps = data.get("tool", {}).get("ci", {}).get("system-dependencies-ubuntu", [])
|
|
101
|
+
if deps:
|
|
102
|
+
print(f"Installing system packages: {' '.join(deps)}")
|
|
103
|
+
subprocess.check_call(["sudo", "apt-get", "update"])
|
|
104
|
+
subprocess.check_call(["sudo", "apt-get", "install", "-y", *deps])
|
|
105
|
+
else:
|
|
106
|
+
print("No CI system dependencies configured for Ubuntu.")
|
|
107
|
+
|
|
108
|
+
- name: Install CI system dependencies (macOS)
|
|
109
|
+
if: runner.os == 'macOS'
|
|
110
|
+
shell: python
|
|
111
|
+
run: |
|
|
112
|
+
import subprocess
|
|
113
|
+
try:
|
|
114
|
+
import tomllib
|
|
115
|
+
except ModuleNotFoundError:
|
|
116
|
+
import pip._vendor.tomli as tomllib
|
|
117
|
+
with open("pyproject.toml", "rb") as f:
|
|
118
|
+
data = tomllib.load(f)
|
|
119
|
+
deps = data.get("tool", {}).get("ci", {}).get("system-dependencies-macos", [])
|
|
120
|
+
if deps:
|
|
121
|
+
print(f"Installing system packages: {' '.join(deps)}")
|
|
122
|
+
subprocess.check_call(["brew", "install", *deps])
|
|
123
|
+
else:
|
|
124
|
+
print("No CI system dependencies configured for macOS.")
|
|
125
|
+
|
|
126
|
+
- name: Install dev deps
|
|
127
|
+
shell: bash
|
|
128
|
+
run: |
|
|
129
|
+
uv pip install -e .[dev] --system
|
|
130
|
+
|
|
131
|
+
- name: Install CI system dependencies (Windows/choco)
|
|
132
|
+
if: runner.os == 'Windows'
|
|
133
|
+
shell: python
|
|
134
|
+
run: |
|
|
135
|
+
import subprocess
|
|
136
|
+
try:
|
|
137
|
+
import tomllib
|
|
138
|
+
except ModuleNotFoundError:
|
|
139
|
+
import pip._vendor.tomli as tomllib
|
|
140
|
+
with open("pyproject.toml", "rb") as f:
|
|
141
|
+
data = tomllib.load(f)
|
|
142
|
+
deps = data.get("tool", {}).get("ci", {}).get("system-dependencies-windows-choco", [])
|
|
143
|
+
if deps:
|
|
144
|
+
print(f"Installing choco packages: {' '.join(deps)}")
|
|
145
|
+
subprocess.check_call(["choco", "install", "-y", *deps])
|
|
146
|
+
else:
|
|
147
|
+
print("No CI choco dependencies configured for Windows.")
|
|
148
|
+
|
|
149
|
+
- name: Install CI pip dependencies (Windows)
|
|
150
|
+
if: runner.os == 'Windows'
|
|
151
|
+
shell: python
|
|
152
|
+
run: |
|
|
153
|
+
import subprocess
|
|
154
|
+
try:
|
|
155
|
+
import tomllib
|
|
156
|
+
except ModuleNotFoundError:
|
|
157
|
+
import pip._vendor.tomli as tomllib
|
|
158
|
+
with open("pyproject.toml", "rb") as f:
|
|
159
|
+
data = tomllib.load(f)
|
|
160
|
+
deps = data.get("tool", {}).get("ci", {}).get("system-dependencies-windows-pip", [])
|
|
161
|
+
if deps:
|
|
162
|
+
print(f"Installing pip packages: {' '.join(deps)}")
|
|
163
|
+
subprocess.check_call(["uv", "pip", "install", *deps, "--system"])
|
|
164
|
+
else:
|
|
165
|
+
print("No CI pip dependencies configured for Windows.")
|
|
166
|
+
|
|
167
|
+
# Self-hosted runners persist ruff cache via RUFF_CACHE_DIR volume mount,
|
|
168
|
+
# so actions/cache is only needed on GitHub-hosted runners.
|
|
169
|
+
- name: Restore ruff cache
|
|
170
|
+
if: runner.environment == 'github-hosted'
|
|
171
|
+
id: ruff-cache
|
|
172
|
+
uses: actions/cache/restore@v6
|
|
173
|
+
with:
|
|
174
|
+
path: .ruff_cache
|
|
175
|
+
key: ruff-${{ runner.os }}-py${{ matrix.python }}-${{ github.sha }}
|
|
176
|
+
restore-keys: |
|
|
177
|
+
ruff-${{ runner.os }}-py${{ matrix.python }}-
|
|
178
|
+
ruff-${{ runner.os }}-
|
|
179
|
+
|
|
180
|
+
- name: Run ruff (lint + format)
|
|
181
|
+
id: ruff
|
|
182
|
+
continue-on-error: true
|
|
183
|
+
shell: bash
|
|
184
|
+
run: |
|
|
185
|
+
ruff check .
|
|
186
|
+
ruff format --check .
|
|
187
|
+
|
|
188
|
+
- name: Run pyright (type check)
|
|
189
|
+
id: pyright
|
|
190
|
+
continue-on-error: true
|
|
191
|
+
shell: bash
|
|
192
|
+
run: pyright
|
|
193
|
+
|
|
194
|
+
- name: Run pytest (tests + coverage)
|
|
195
|
+
id: pytest
|
|
196
|
+
continue-on-error: true
|
|
197
|
+
shell: bash
|
|
198
|
+
env:
|
|
199
|
+
TEST_VERBOSE: "1"
|
|
200
|
+
# Write coverage SQLite database to local disk — network mounts
|
|
201
|
+
# and stale journal files cause "database is locked" errors.
|
|
202
|
+
COVERAGE_FILE: "${{ runner.temp }}/.coverage"
|
|
203
|
+
run: >-
|
|
204
|
+
pytest -m "${{ env.PYTEST_MARKER_EXPR }}"
|
|
205
|
+
--cov=${{ env.SRC_PATH }}/${{ env.PACKAGE_MODULE }}
|
|
206
|
+
--cov-report=term-missing
|
|
207
|
+
--cov-report=xml:${{ env.COV_REPORT_FILE }}
|
|
208
|
+
--cov-fail-under=${{ env.COV_FAIL_UNDER }}
|
|
209
|
+
${{ env.PYTEST_VERBOSITY }}
|
|
210
|
+
|
|
211
|
+
- name: Upload coverage to Codecov
|
|
212
|
+
if: >-
|
|
213
|
+
always()
|
|
214
|
+
&& steps.pytest.outcome == 'success'
|
|
215
|
+
&& matrix.os == 'ubuntu-latest'
|
|
216
|
+
&& matrix.python == needs.setup.outputs.python-latest
|
|
217
|
+
uses: codecov/codecov-action@v7
|
|
218
|
+
with:
|
|
219
|
+
files: ${{ env.COV_REPORT_FILE }}
|
|
220
|
+
fail_ci_if_error: false
|
|
221
|
+
|
|
222
|
+
- name: Run import-linter (architecture)
|
|
223
|
+
id: importlinter
|
|
224
|
+
continue-on-error: true
|
|
225
|
+
shell: bash
|
|
226
|
+
run: lint-imports
|
|
227
|
+
|
|
228
|
+
- name: Run bandit (security scan)
|
|
229
|
+
id: bandit
|
|
230
|
+
continue-on-error: true
|
|
231
|
+
shell: bash
|
|
232
|
+
run: bandit -q -c pyproject.toml -r ${{ env.SRC_PATH }}/${{ env.PACKAGE_MODULE }} ${{ env.BANDIT_SKIP_FLAG }}
|
|
233
|
+
|
|
234
|
+
- name: Run pip-audit (vulnerability scan)
|
|
235
|
+
id: pipaudit
|
|
236
|
+
continue-on-error: true
|
|
237
|
+
shell: python
|
|
238
|
+
run: |
|
|
239
|
+
import subprocess, sys, tempfile
|
|
240
|
+
import rtoml
|
|
241
|
+
from pathlib import Path
|
|
242
|
+
|
|
243
|
+
# Audit the project's OWN resolved dependency tree, not the ambient
|
|
244
|
+
# environment. "Install dev deps" uses --system, so the interpreter
|
|
245
|
+
# being audited is the runner image's, and that image ships packages
|
|
246
|
+
# this project neither declares nor distributes (setuptools, pip,
|
|
247
|
+
# wheel). Auditing those reported CVEs no consumer of this project is
|
|
248
|
+
# exposed to, and a scan that is permanently yellow is a scan everyone
|
|
249
|
+
# learns to ignore. Resolving pyproject.toml here keeps the result
|
|
250
|
+
# identical on every OS/python and dependent only on what we declare.
|
|
251
|
+
data = rtoml.load(Path("pyproject.toml"))
|
|
252
|
+
|
|
253
|
+
# Not every project declares dev dependencies, and those that do may use
|
|
254
|
+
# either an extra or a PEP 735 group. Asking uv for one that does not
|
|
255
|
+
# exist is a hard error ("Requested extra not found"), which would leave
|
|
256
|
+
# the audit permanently broken here rather than merely noisy, so select
|
|
257
|
+
# the flag from what this project actually declares.
|
|
258
|
+
selector = []
|
|
259
|
+
if "dev" in data.get("project", {}).get("optional-dependencies", {}):
|
|
260
|
+
selector = ["--extra", "dev"]
|
|
261
|
+
elif "dev" in data.get("dependency-groups", {}):
|
|
262
|
+
selector = ["--group", "dev"]
|
|
263
|
+
|
|
264
|
+
tmp = Path(tempfile.mkdtemp())
|
|
265
|
+
req = tmp / "compiled-requirements.txt"
|
|
266
|
+
subprocess.check_call(
|
|
267
|
+
["uv", "pip", "compile", *selector, "pyproject.toml", "-o", str(req), "--quiet"]
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
# Drop direct URL references ("pkg @ git+https://...") before auditing.
|
|
271
|
+
# pip-audit cannot audit those (they are not on PyPI) but, given a
|
|
272
|
+
# requirements file, first tries to `git clone` each one to resolve a
|
|
273
|
+
# version - a slow, credential-dependent fetch. No public project here
|
|
274
|
+
# uses one today, yet "allow-direct-references" is enabled, so this
|
|
275
|
+
# guards the day one appears and keeps this step identical to the
|
|
276
|
+
# default_cicd_private template's.
|
|
277
|
+
audit_req = tmp / "audit-requirements.txt"
|
|
278
|
+
kept, dropped = [], []
|
|
279
|
+
for line in req.read_text(encoding="utf-8").splitlines():
|
|
280
|
+
if " @ " in line and not line.lstrip().startswith("#"):
|
|
281
|
+
dropped.append(line.split(" @ ", 1)[0].strip())
|
|
282
|
+
else:
|
|
283
|
+
kept.append(line)
|
|
284
|
+
audit_req.write_text("\n".join(kept) + "\n", encoding="utf-8")
|
|
285
|
+
if dropped:
|
|
286
|
+
# Never drop coverage silently: name what is not being audited here.
|
|
287
|
+
print(f"::notice::pip-audit: not auditing {len(dropped)} direct-URL dependency/ies "
|
|
288
|
+
f"(audited in their own repo): {', '.join(sorted(dropped))}")
|
|
289
|
+
|
|
290
|
+
req = audit_req
|
|
291
|
+
vulns = data.get("tool", {}).get("pip-audit", {}).get("ignore-vulns", [])
|
|
292
|
+
# --no-deps: the compiled file is already a complete pinned resolution,
|
|
293
|
+
# so pip-audit must audit it verbatim rather than re-resolving it.
|
|
294
|
+
cmd = ["pip-audit", "--no-deps", "-r", str(req)]
|
|
295
|
+
for v in vulns:
|
|
296
|
+
cmd.extend(["--ignore-vuln", v])
|
|
297
|
+
sys.exit(subprocess.call(cmd))
|
|
298
|
+
|
|
299
|
+
- name: Check all steps passed
|
|
300
|
+
shell: bash
|
|
301
|
+
run: |
|
|
302
|
+
if [[ "${{ steps.ruff.outcome }}" != "success" ]]; then
|
|
303
|
+
echo "::error::Ruff check failed"
|
|
304
|
+
exit 1
|
|
305
|
+
fi
|
|
306
|
+
if [[ "${{ steps.pyright.outcome }}" != "success" ]]; then
|
|
307
|
+
echo "::error::Pyright check failed"
|
|
308
|
+
exit 1
|
|
309
|
+
fi
|
|
310
|
+
if [[ "${{ steps.pytest.outcome }}" != "success" ]]; then
|
|
311
|
+
echo "::error::Pytest failed"
|
|
312
|
+
exit 1
|
|
313
|
+
fi
|
|
314
|
+
if [[ "${{ steps.importlinter.outcome }}" != "success" ]]; then
|
|
315
|
+
echo "::error::Import-linter check failed"
|
|
316
|
+
exit 1
|
|
317
|
+
fi
|
|
318
|
+
if [[ "${{ steps.bandit.outcome }}" != "success" ]]; then
|
|
319
|
+
echo "::error::Bandit security scan failed"
|
|
320
|
+
exit 1
|
|
321
|
+
fi
|
|
322
|
+
if [[ "${{ steps.pipaudit.outcome }}" != "success" ]]; then
|
|
323
|
+
echo "::warning::pip-audit vulnerability scan failed"
|
|
324
|
+
fi
|
|
325
|
+
echo "All checks passed!"
|
|
326
|
+
|
|
327
|
+
- name: Build wheel/sdist
|
|
328
|
+
shell: bash
|
|
329
|
+
run: uv build
|
|
330
|
+
|
|
331
|
+
- name: Verify wheel install in clean env
|
|
332
|
+
shell: bash
|
|
333
|
+
run: |
|
|
334
|
+
uv venv .venv_wheel
|
|
335
|
+
. .venv_wheel/bin/activate 2>/dev/null || . .venv_wheel/Scripts/activate 2>/dev/null
|
|
336
|
+
uv pip install dist/*.whl
|
|
337
|
+
"$CLI_BIN" --version 2>/dev/null || python -m "$PACKAGE_MODULE" --version
|
|
338
|
+
|
|
339
|
+
- name: Prune uv cache
|
|
340
|
+
continue-on-error: true
|
|
341
|
+
shell: bash
|
|
342
|
+
run: uv cache prune --ci
|
|
343
|
+
|
|
344
|
+
- name: Save ruff cache
|
|
345
|
+
if: always() && runner.environment == 'github-hosted' && steps.ruff-cache.outputs.cache-hit != 'true'
|
|
346
|
+
uses: actions/cache/save@v6
|
|
347
|
+
with:
|
|
348
|
+
path: .ruff_cache
|
|
349
|
+
key: ruff-${{ runner.os }}-py${{ matrix.python }}-${{ github.sha }}
|
|
350
|
+
|
|
351
|
+
pipx-uv:
|
|
352
|
+
name: pipx/uv verification (ubuntu)
|
|
353
|
+
runs-on: ubuntu-latest
|
|
354
|
+
steps:
|
|
355
|
+
- uses: actions/checkout@v7
|
|
356
|
+
- uses: actions/setup-python@v7
|
|
357
|
+
with:
|
|
358
|
+
python-version: "3.14"
|
|
359
|
+
|
|
360
|
+
- name: Install uv
|
|
361
|
+
uses: astral-sh/setup-uv@v7
|
|
362
|
+
with:
|
|
363
|
+
enable-cache: true
|
|
364
|
+
prune-cache: false
|
|
365
|
+
|
|
366
|
+
- name: Extract project metadata
|
|
367
|
+
id: metadata
|
|
368
|
+
uses: ./.github/actions/extract-metadata
|
|
369
|
+
|
|
370
|
+
- name: Build wheel
|
|
371
|
+
run: uv build
|
|
372
|
+
- name: pipx install from wheel
|
|
373
|
+
run: |
|
|
374
|
+
uv pip install --system pipx
|
|
375
|
+
pipx ensurepath
|
|
376
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
377
|
+
pipx install dist/*.whl
|
|
378
|
+
"$CLI_BIN" --version
|
|
379
|
+
|
|
380
|
+
- name: uv tool install
|
|
381
|
+
run: |
|
|
382
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
383
|
+
uv tool install --force .
|
|
384
|
+
"$CLI_BIN" --version
|
|
385
|
+
|
|
386
|
+
- name: Prune uv cache
|
|
387
|
+
continue-on-error: true
|
|
388
|
+
run: uv cache prune --ci
|
|
389
|
+
|
|
390
|
+
notebooks:
|
|
391
|
+
name: Execute notebooks (ubuntu, Python 3.14)
|
|
392
|
+
runs-on: ubuntu-latest
|
|
393
|
+
steps:
|
|
394
|
+
- uses: actions/checkout@v7
|
|
395
|
+
- uses: actions/setup-python@v7
|
|
396
|
+
with:
|
|
397
|
+
python-version: "3.14"
|
|
398
|
+
|
|
399
|
+
- name: Install uv
|
|
400
|
+
uses: astral-sh/setup-uv@v7
|
|
401
|
+
with:
|
|
402
|
+
enable-cache: true
|
|
403
|
+
prune-cache: false
|
|
404
|
+
|
|
405
|
+
- name: Install notebook runner deps
|
|
406
|
+
run: |
|
|
407
|
+
uv pip install --system nbclient nbformat ipykernel jupyter_client
|
|
408
|
+
python -m ipykernel install --user --name python3 --display-name "Python 3"
|
|
409
|
+
- name: Execute Quickstart notebook
|
|
410
|
+
env:
|
|
411
|
+
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
|
412
|
+
PIP_NO_INPUT: "1"
|
|
413
|
+
run: |
|
|
414
|
+
python - << 'PY'
|
|
415
|
+
from pathlib import Path
|
|
416
|
+
|
|
417
|
+
import nbformat
|
|
418
|
+
from nbclient import NotebookClient
|
|
419
|
+
|
|
420
|
+
nb_path = Path('notebooks/Quickstart.ipynb')
|
|
421
|
+
if not nb_path.exists():
|
|
422
|
+
raise SystemExit(f"Notebook not found: {nb_path}")
|
|
423
|
+
|
|
424
|
+
notebook = nbformat.read(nb_path, as_version=4)
|
|
425
|
+
client = NotebookClient(
|
|
426
|
+
notebook,
|
|
427
|
+
timeout=900,
|
|
428
|
+
kernel_name='python3',
|
|
429
|
+
allow_errors=False,
|
|
430
|
+
)
|
|
431
|
+
client.execute()
|
|
432
|
+
|
|
433
|
+
out_path = Path('notebooks/Quickstart-executed.ipynb')
|
|
434
|
+
nbformat.write(notebook, out_path)
|
|
435
|
+
print(f"Executed notebook written to: {out_path}")
|
|
436
|
+
PY
|