diff --git a/.gitignore b/.gitignore index aaf8f06..71d8916 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +@ -1,197 +0,0 @@ /misc/ /Temp/ /Downloads/ @@ -194,4 +195,4 @@ pdm.lock /.idea/modules.xml /.idea/inspectionProfiles/profiles_settings.xml /.idea/pyplayready.iml -/.idea/vcs.xml +/.idea/vcs.xml \ No newline at end of file diff --git a/.idea/PlayReady-Amazon-Tool-main.iml b/.idea/PlayReady-Amazon-Tool-main.iml index f58bb3c..bd20c4b 100644 --- a/.idea/PlayReady-Amazon-Tool-main.iml +++ b/.idea/PlayReady-Amazon-Tool-main.iml @@ -2,9 +2,6 @@ - - - diff --git a/.idea/runConfigurations/poetry.xml b/.idea/runConfigurations/poetry.xml deleted file mode 100644 index 7534934..0000000 --- a/.idea/runConfigurations/poetry.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - \ No newline at end of file diff --git a/ATVP.txt b/ATVP.txt index 22c42d6..28c4429 100644 --- a/ATVP.txt +++ b/ATVP.txt @@ -1,11 +1,5 @@ -https://tv.apple.com/us/show/ray-donovan/umc.cmc.hr7pnm1wbx98w1h3pg7dfbey -https://tv.apple.com/us/show/party-down/umc.cmc.6myol1kgcd19kerlujhtcr8kg https://tv.apple.com/us/show/mythic-quest/umc.cmc.1nfdfd5zlk05fo1bwwetzldy3 https://tv.apple.com/us/show/the-completely-made-up-adventures-of-dick-turpin/umc.cmc.37r7vskzmm8hk2pfbzaxlcwzg -https://tv.apple.com/us/show/the-office-superfan-episodes/umc.cmc.3r3om9j6edlrnznl5pfassikv -https://tv.apple.com/us/show/trailer-park-boys-the-swearnet-show/umc.cmc.71tbyxchxiwotaysuuztm8p54 -https://tv.apple.com/us/show/fridays/umc.cmc.ve44y99fmo41lok4mx7azvfi -https://tv.apple.com/us/show/utopia/umc.cmc.4uzbqvarwjrbkqz92796oelqj https://tv.apple.com/us/movie/oceans-eleven/umc.cmc.4mt9j4jqou4mlup1pc9riyo63 https://tv.apple.com/us/movie/bullet-train/umc.cmc.5erhpztw3spfkfi0daabkmaq0 @@ -82,4 +76,10 @@ https://tv.apple.com/us/show/robot-chicken/umc.cmc.5vh2acwvaldmwdqj1qibtl02u | R https://tv.apple.com/us/show/the-state/umc.cmc.5af6lx6evkseyhotjzhr16oot | The State - Apple TV https://tv.apple.com/us/show/upright-citizens-brigade/umc.cmc.638n6gvt13rg3w8g24h1chmdr | Upright Citizens Brigade - Apple TV https://tv.apple.com/us/show/fridays/umc.cmc.ve44y99fmo41lok4mx7azvfi | Fridays - Apple TV -https://tv.apple.com/us/show/drunk-history/umc.cmc.2fai5tmqz2z6g9iy8er8ft11m | Drunk History - Apple TV \ No newline at end of file +https://tv.apple.com/us/show/drunk-history/umc.cmc.2fai5tmqz2z6g9iy8er8ft11m | Drunk History - Apple TV +https://tv.apple.com/us/show/ray-donovan/umc.cmc.hr7pnm1wbx98w1h3pg7dfbey +https://tv.apple.com/us/show/party-down/umc.cmc.6myol1kgcd19kerlujhtcr8kg +https://tv.apple.com/us/show/the-office-superfan-episodes/umc.cmc.3r3om9j6edlrnznl5pfassikv +https://tv.apple.com/us/show/trailer-park-boys-the-swearnet-show/umc.cmc.71tbyxchxiwotaysuuztm8p54 +https://tv.apple.com/us/show/fridays/umc.cmc.ve44y99fmo41lok4mx7azvfi +https://tv.apple.com/us/show/utopia/umc.cmc.4uzbqvarwjrbkqz92796oelqj \ No newline at end of file diff --git a/How to use VT.pdf b/How to use VT.pdf new file mode 100644 index 0000000..b49364f Binary files /dev/null and b/How to use VT.pdf differ diff --git a/README.md b/README.md index 7418d67..7b3a86e 100644 --- a/README.md +++ b/README.md @@ -1,210 +1,23 @@ -# VineTrimmer-PlayReady -A tool to download and remove DRM from streaming services. A version of an old fork of [devine](https://github.com/devine-dl/devine). -Modified to remove Playready DRM instead of Widevine. - -## Features - - Progress Bars for decryption ([mp4decrypt](https://github.com/chu23465/bentoOldFork), Shaka) - - Refresh Token fixed for Amazon service - - Reprovision .prd after a week - - ISM manifest support (Microsoft Smooth Streaming) (Few features to be added) - - N_m3u8DL-RE downloader support +Hi +, I'm PlayReady -## Usage +This is me Sofiya, I am posting this to show how we can use SL2000 Certificate to do amazon using Playready drm. +"---Always Work Hard and Trust the Process---" -1. Run `install.bat` - -2. Activate venv using `venv.cmd`. +Amazon Demonstration using SL2000 + +WE have all Certificates SL2000 & SL 30000 +We have all codes to disney and all sites +This is posted to punish the people who are making playready easy available + +If you wanna collabrate & need support mail us on Playreadydrm@proton.me + +Update : API USED IN THIS IS DOWN DUE TO DDOS +Command used + +poetry run vt dl -al en -sl en -q 1080 Amazon -b cbr -vq hd 0NRT15S2XG06SG5HBV5NQAW3E3 -### Config +https://github.com/Playreadydrm/PlayReady-Amazon-Tool/assets/170321722/1fdacab6-d1db-41f4-82f6-a73b5e1286c8 -`vinetrimmer.yml` located within the `/vinetrimmer/` folder. - -`decryptor:` either `mp4decrypt` or `packager` - -(shaka-packager fails to decrypt files downloaded from MSS manifests) - -`tag:` tag for your release group - -CDM can be configured per service or per profile. - -``` -cdm: - default: {text} - Amazon: {text} -``` - -All other option can be left to defaults, unless you know what you are doing. - -### General Options - -Usage: vt.cmd [OPTIONS] COMMAND [ARGS]... - -Options: -| Command line argument | Description | Default Value | -|----------------------------|-----------------------------------------------------------------------------------------------|-----------------------------------| -| -d, --debug | Flag to enable debug logging | False | -| -p, --profile | Profile to use when multiple profiles are defined for a service. | "default" | -| -q, --quality | Download Resolution | 1080 | -| -v, --vcodec | Video Codec | H264 | -| -a, --acodec | Audio Codec | None | -| -vb, --vbitrate | Video Bitrate | Max | -| -ab, --abitrate | Audio Bitrate | Max | -| -aa, --atmos | Prefer Atmos Audio | False | -| -r, --range | Video Color Range `HDR`, `HDR10`, `DV`, `SDR` | SDR | -| -w, --wanted | Wanted episodes, e.g. `S01-S05,S07`, `S01E01-S02E03`, `S02-S02E03` | Default to all | -| -al, --alang | Language wanted for audio. | Defaults to original language | -| -sl, --slang | Language wanted for subtitles. | Defaults to original language | -| --proxy | Proxy URI to use. If a 2-letter country is provided, it will try get a proxy from the config. | None | -| -A, --audio-only | Only download audio tracks. | False | -| -S, --subs-only | Only download subtitle tracks. | False | -| -C, --chapters-only | Only download chapters. | False | -| -ns, --no-subs | Do not download subtitle tracks. | False | -| -na, --no-audio | Do not download audio tracks. | False | -| -nv, --no-video | Do not download video tracks. | False | -| -nc, --no-chapters | Do not download chapters tracks. | False | -| -ad, --audio-description | Download audio description tracks. | False | -| --list | Skip downloading and list available tracks and what tracks would have been downloaded. | False | -| --selected | List selected tracks and what tracks are downloaded. | False | -| --cdm | Override the CDM that will be used for decryption. | None | -| --keys | Skip downloading, retrieve the decryption keys (via CDM or Key Vaults) and print them. | False | -| --cache | Disable the use of the CDM and only retrieve decryption keys from Key Vaults. If a needed key is unable to be retrieved from any Key Vaults, the title is skipped.| False | -| --no-cache | Disable the use of Key Vaults and only retrieve decryption keys from the CDM. | False | -| --no-proxy | Force disable all proxy use. | False | -| -nm, --no-mux | Do not mux the downloaded and decrypted tracks. | False | -| --mux | Force muxing when using --audio-only/--subs-only/--chapters-only. | False | -| -?, -h, --help | Show this message and exit. | | - - -COMMAND :- - -| Alaias | Command | Service Link | -|--------|---------------|--------------------------------------------| -| AMZN | Amazon | https://amazon.com, https://primevideo.com | -| ATVP | AppleTVPlus | https://tv.apple.com | -| MAX | Max | https://max.com | -| NF | Netflix | https://netflix.com | - -### Amazon Specific Options - -Usage: vt.cmd AMZN [OPTIONS] [TITLE] - - Service code for Amazon VOD (https://amazon.com) and Amazon Prime Video (https://primevideo.com). - - Authorization: Cookies - - Security: - ``` - UHD@L1/SL3000 - FHD@L3(ChromeCDM)/SL2000 - SD@L3 - - Certain SL2000 can do UHD - ``` - Maintains their own license server like Netflix, be cautious. - - Region is chosen automatically based on domain extension found in cookies. - Prime Video specific code will be run if the ASIN is detected to be a prime video variant. - Use 'Amazon Video ASIN Display' for Tampermonkey addon for ASIN - https://greasyfork.org/en/scripts/381997-amazon-video-asin-display - - vt dl --list -z uk -q 1080 Amazon B09SLGYLK8 - -Below flags to be passed after the `AMZN` or `Amazon` keyword in command. - -| Command Line Switch | Description | -|-------------------------------------|-----------------------------------------------------------------------------------------------------| -| -b, --bitrate | Video Bitrate Mode to download in. CVBR=Constrained Variable Bitrate, CBR=Constant Bitrate. (CVBR or CBR or CVBR+CBR) | -| -c, --cdn | CDN to download from, defaults to the CDN with the highest weight set by Amazon. | -| -vq, --vquality | Manifest quality to request. (SD or HD or UHD) | -| -s, --single | Force single episode/season instead of getting series ASIN. | -| -am, --amanifest | Manifest to use for audio. Defaults to H265 if the video manifest is missing 640k audio. (CVBR or CBR or H265) | -| -aq, --aquality | Manifest quality to request for audio. Defaults to the same as --quality. (SD or HD or UHD) | -| -ism, --ism | Set manifest override to SmoothStreaming. Defaults to DASH w/o this flag. | -| -?, -h, --help | Show this message and exit. | - -To get UHD/4k with Amazon, navigate to - - -``` -https://www.primevideo.com/region/eu/ontv/code?ref_=atv_auth_red_aft -``` - -Login and get to the code pair page. Extract cookies from that page using [Open Cookies.txt](https://chromewebstore.google.com/detail/open-cookiestxt/gdocmgbfkjnnpapoeobnolbbkoibbcif). - -Save it to the path `vinetrimmer/Cookies/Amazon/default.txt`. - -When caching cookies, use a profile without PIN. Otherwise it causes errors. - -### Peacock - - - PCOK bans leaked certs quickly (for 4k), be cautious. - -### Example Command - -Amazon Example: - -```bash -poetry run vt dl -al en -sl en --selected -q 2160 -r HDR -w S01E18-S01E25 AMZN -b CBR --ism 0IQZZIJ6W6TT2CXPT6ZOZYX396 -``` - -Above command: - - gets english subtitles + audio, - - selects the HDR + 4K track, - - gets episodes from S01E18 to S01E25 from Amazon - - with CBR bitrate, - - tries to force ISM - - and the title-ID is 0IQZZIJ6W6TT2CXPT6ZOZYX396 - -AppleTV Example: - -```bash -poetry run vt dl -al en -sl en --list -q 720 --proxy http://192.168.0.99:9766 -w S01E01 ATVP umc.cmc.1nfdfd5zlk05fo1bwwetzldy3 -``` - -Above command: - - gets english subtitles + audio, - - lists all possible qualities, - - selects 720p video track, - - uses the proxy for licensing, - - gets the first episode of first season (i.e S01E01) - - of the title umc.cmc.1nfdfd5zlk05fo1bwwetzldy3 - - -## Proxy -I recommend [Windscribe](https://windscribe.com/). You can sign up, getting 10 GB of traffic credit every month for free. We use the VPN for everything except downloading video/audio. -Tested so far on Amazon, AppleTVPlus, Max. - -### Steps: -1. For each service, within get_tracks() function we do this below. - ```python - for track in tracks: - track.needs_proxy = False - ``` - - This flag signals that this track does not need a proxy and a proxy will not be passed to downloader even if proxy given in CLI options. - -2. Download Windscribe app and install it. - -3. Go to `Options` -> `Connection` -> `Split Tunneling`. Enable it. - - Set `Mode` as `Inclusive`. - -5. Go to `Options` -> `Connection` -> `Proxy Gateway`. Enable it. Select `Proxy Type` as `HTTP`. - - Copy the `IP` field (will look something like `192.168.0.141:9766`) - - Pass above copied to Vinetrimmer with the proxy flag like below. - - ```bash - ...(other flags)... --proxy http://192.168.0.141:9766 ....... - ``` - -## Other - - For `--keys` to work with ATVP you need to pass the `--no-subs` flag also - - Nuikta compile is an option to run on various linux distributions. - - Errors arise when running VT within Docker or Conda like python distributions. Make sure to use proper python3. - - To use programs in `scripts` folder, first activate venv then, then - - ```bash - poetry run python scripts/ParseKeybox.py - ``` diff --git a/amazon_old.py b/amazon_old.py new file mode 100644 index 0000000..8d1183d --- /dev/null +++ b/amazon_old.py @@ -0,0 +1,1050 @@ +from __future__ import annotations + +import base64 +import hashlib +import json +import os +import re +import time +from collections import defaultdict +from pathlib import Path +from urllib.parse import urlencode + +import click +import jsonpickle +import requests +from click import Context +from langcodes import Language +from tldextract import tldextract +from click.core import ParameterSource + +from vinetrimmer.objects import TextTrack, Title, Tracks +from vinetrimmer.objects.tracks import MenuTrack +from vinetrimmer.services.BaseService import BaseService +from vinetrimmer.utils import is_close_match +from vinetrimmer.utils.Logger import Logger +from vinetrimmer.utils.widevine.device import LocalDevice + + +class Amazon(BaseService): + """ + Service code for Amazon VOD (https://amazon.com) and Amazon Prime Video (https://primevideo.com). + + \b + Authorization: Cookies + Security: UHD@L1 FHD@L3(ChromeCDM) SD@L3, Maintains their own license server like Netflix, be cautious. + + \b + Region is chosen automatically based on domain extension found in cookies. + Prime Video specific code will be run if the ASIN is detected to be a prime video variant. + Use 'Amazon Video ASIN Display' for Tampermonkey addon for ASIN + https://greasyfork.org/en/scripts/381997-amazon-video-asin-display + + vt dl --list -z uk -q 1080 Amazon B09SLGYLK8 + """ + + ALIASES = ["AMZN", "amazon"] + TITLE_RE = r"^(?:https?://(?:www\.)?(?Pamazon\.(?Pcom|co\.uk|de|co\.jp)|primevideo\.com)(?:/.+)?/)?(?P[A-Z0-9]{10,}|amzn1\.dv\.gti\.[a-f0-9-]+)" # noqa: E501 + + REGION_TLD_MAP = { + "au": "com.au", + "br": "com.br", + "jp": "co.jp", + "mx": "com.mx", + "tr": "com.tr", + "gb": "co.uk", + "us": "com", + } + VIDEO_RANGE_MAP = { + "SDR": "None", + "HDR10": "Hdr10", + "DV": "DolbyVision", + } + + @staticmethod + @click.command(name="Amazon", short_help="https://amazon.com, https://primevideo.com", help=__doc__) + @click.argument("title", type=str, required=False) + @click.option("-b", "--bitrate", default="CBR", + type=click.Choice(["CVBR", "CBR", "CVBR+CBR"], case_sensitive=False), + help="Video Bitrate Mode to download in. CVBR=Constrained Variable Bitrate, CBR=Constant Bitrate.") + @click.option("-c", "--cdn", default=None, type=str, + help="CDN to download from, defaults to the CDN with the highest weight set by Amazon.") + # UHD, HD, SD. UHD only returns HEVC, ever, even for <=HD only content + @click.option("-vq", "--vquality", default="HD", + type=click.Choice(["SD", "HD", "UHD"], case_sensitive=False), + help="Manifest quality to request.") + @click.option("-s", "--single", is_flag=True, default=False, + help="Force single episode/season instead of getting series ASIN.") + @click.option("-am", "--amanifest", default="H265", + type=click.Choice(["CVBR", "CBR", "H265"], case_sensitive=False), + help="Manifest to use for audio. Defaults to H265 if the video manifest is missing 640k audio.") + @click.option("-aq", "--aquality", default="SD", + type=click.Choice(["SD", "HD", "UHD"], case_sensitive=False), + help="Manifest quality to request for audio. Defaults to the same as --quality.") + @click.pass_context + def cli(ctx, **kwargs): + return Amazon(ctx, **kwargs) + + def __init__(self, ctx, title, bitrate: str, cdn: str, vquality: str, single: bool, + amanifest: str, aquality: str): + + + m = self.parse_title(ctx, title) + self.bitrate = bitrate + self.bitrate_source = ctx.get_parameter_source("bitrate") + self.cdn = cdn + self.vquality = vquality + self.vquality_source = ctx.get_parameter_source("vquality") + self.single = single + self.amanifest = amanifest + self.aquality = aquality + super().__init__(ctx) + + assert ctx.parent is not None + + self.vcodec = ctx.parent.params["vcodec"] or "H264" + self.range = ctx.parent.params["range_"] or "SDR" + self.chapters_only = ctx.parent.params["chapters_only"] + self.atmos = ctx.parent.params["atmos"] + self.quality = ctx.parent.params.get("quality") or 1080 + + self.cdm = ctx.obj.cdm + self.profile = ctx.obj.profile + + self.region: dict[str, str] = {} + self.endpoints: dict[str, str] = {} + self.device: dict[str, str] = {} + + self.pv = False + self.device_token = None + self.device_id: None + self.customer_id = None + self.client_id = "f22dbddb-ef2c-48c5-8876-bed0d47594fd" # browser client id + + if self.vquality_source != ParameterSource.COMMANDLINE: + if 0 < self.quality <= 576 and self.range == "SDR": + self.log.info(" + Setting manifest quality to SD") + self.vquality = "SD" + + if self.quality > 1080: + self.log.info(" + Setting manifest quality to UHD to be able to get 2160p video track") + self.vquality = "UHD" + + self.vquality = self.vquality or "HD" + + if self.bitrate_source != ParameterSource.COMMANDLINE: + if self.vcodec == "H265" and self.range == "SDR" and self.bitrate != "CVBR+CBR": + self.bitrate = "CVBR+CBR" + self.log.info(" + Changed bitrate mode to CVBR+CBR to be able to get H.265 SDR video track") + + if self.vquality == "UHD" and self.range != "SDR" and self.bitrate != "CBR": + self.bitrate = "CBR" + self.log.info(f" + Changed bitrate mode to CBR to be able to get highest quality UHD {self.range} video track") + + self.orig_bitrate = self.bitrate + + self.configure() + + # Abstracted functions + + def get_titles(self): + res = self.session.get( + url=self.endpoints["details"], + params={ + "titleID": self.title, + "isElcano": "1", + "sections": ["Atf", "Btf"] + }, + headers={ + "Accept": "application/json" + } + ) + + if not res.ok: + raise self.log.exit(f"Unable to get title: {res.text} [{res.status_code}]") + + data = res.json()["widgets"] + product_details = data.get("productDetails", {}).get("detail") + + if not product_details: + error = res.json()["degradations"][0] + raise self.log.exit(f"Unable to get title: {error['message']} [{error['code']}]") + + titles = [] + + if data["pageContext"]["subPageType"] == "Movie": + card = data["productDetails"]["detail"] + titles.append(Title( + id_=card["catalogId"], + type_=Title.Types.MOVIE, + name=product_details["title"], + #year=card["releaseYear"], + year=card.get("releaseYear", ""), + # language is obtained afterward + original_lang=None, + source=self.ALIASES[0], + service_data=card + )) + else: + cards = [ + x["detail"] + for x in data["titleContent"][0]["cards"] + if not self.single or + (self.single and self.title in data["self"]["asins"]) or + (self.single and self.title in x["self"]["asins"]) + ] + for card in cards: + episode_number = card.get("episodeNumber", 0) + if episode_number != 0: + titles.append(Title( + id_=card["catalogId"], + type_=Title.Types.TV, + name=product_details["parentTitle"], + season=product_details["seasonNumber"], + episode=episode_number, + episode_name=card["title"], + # language is obtained afterward + original_lang=None, + source=self.ALIASES[0], + service_data=card + )) + + if not self.single: + temp_title = self.title + temp_single = self.single + + self.single = True + for season in data["seasonSelector"]: + if data["self"]["asins"][0] in season["self"]["asins"]: + continue + self.title = season["self"]["asins"][0] + for title in self.get_titles(): + titles.append(title) + + self.title = temp_title + self.single = temp_single + + if titles: + # TODO: Needs playback permission on first title, title needs to be available + original_lang = self.get_original_language(self.get_manifest( + next((x for x in titles if x.type == Title.Types.MOVIE or x.episode > 0), titles[0]), + video_codec=self.vcodec, + bitrate_mode=self.bitrate, + quality=self.vquality, + ignore_errors=True + )) + if original_lang: + for title in titles: + title.original_lang = Language.get(original_lang) + else: + #self.log.warning(" - Unable to obtain the title's original language, setting 'en' default...") + for title in titles: + title.original_lang = Language.get("en") + return titles + + def get_tracks(self, title: Title) -> Tracks: + tracks = Tracks() + if self.chapters_only: + return [] + + manifest, chosen_manifest, tracks = self.get_best_quality(title) + + manifest = self.get_manifest( + title, + video_codec=self.vcodec, + bitrate_mode=self.bitrate, + quality=self.vquality, + hdr=self.range, + ignore_errors=False + + ) + + # Move rightsException termination here so that script can attempt continuing + if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: + self.log.error(" - The profile used does not have the rights to this title.") + return + + self.customer_id = manifest["returnedTitleRendition"]["selectedEntitlement"]["grantedByCustomerId"] + + default_url_set = manifest["playbackUrls"]["urlSets"][manifest["playbackUrls"]["defaultUrlSetId"]] + encoding_version = default_url_set["urls"]["manifest"]["encodingVersion"] + self.log.info(f" + Detected encodingVersion={encoding_version}") + + chosen_manifest = self.choose_manifest(manifest, self.cdn) + + if not chosen_manifest: + raise self.log.exit(f"No manifests available") + + manifest_url = self.clean_mpd_url(chosen_manifest["avUrlInfoList"][0]["url"], False) + self.log.debug(manifest_url) + self.log.info(" + Downloading Manifest") + + if chosen_manifest["streamingTechnology"] == "DASH": + tracks = Tracks([ + x for x in iter(Tracks.from_mpd( + url=manifest_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + elif chosen_manifest["streamingTechnology"] == "SmoothStreaming": + tracks = Tracks([ + x for x in iter(Tracks.from_ism( + url=manifest_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + else: + raise self.log.exit(f"Unsupported manifest type: {chosen_manifest['streamingTechnology']}") + + need_separate_audio = ((self.aquality or self.vquality) != self.vquality + or self.amanifest == "CVBR" and (self.vcodec, self.bitrate) != ("H264", "CVBR") + or self.amanifest == "CBR" and (self.vcodec, self.bitrate) != ("H264", "CBR") + or self.amanifest == "H265" and self.vcodec != "H265" + or self.amanifest != "H265" and self.vcodec == "H265") + + if not need_separate_audio: + audios = defaultdict(list) + for audio in tracks.audios: + audios[audio.language].append(audio) + + for lang in audios: + if not any((x.bitrate or 0) >= 640000 for x in audios[lang]): + need_separate_audio = True + break + + if need_separate_audio and not self.atmos: + manifest_type = self.amanifest or "H265" + self.log.info(f"Getting audio from {manifest_type} manifest for potential higher bitrate or better codec") + audio_manifest = self.get_manifest( + title=title, + video_codec="H265" if manifest_type == "H265" else "H264", + bitrate_mode="CVBR" if manifest_type != "CBR" else "CBR", + quality=self.aquality or self.vquality, + hdr=None, + ignore_errors=True + ) + if not audio_manifest: + self.log.warning(f" - Unable to get {manifest_type} audio manifests, skipping") + elif not (chosen_audio_manifest := self.choose_manifest(audio_manifest, self.cdn)): + self.log.warning(f" - No {manifest_type} audio manifests available, skipping") + else: + audio_mpd_url = self.clean_mpd_url(chosen_audio_manifest["avUrlInfoList"][0]["url"], optimise=False) + self.log.debug(audio_mpd_url) + self.log.info(" + Downloading HEVC manifest") + + try: + audio_mpd = Tracks([ + x for x in iter(Tracks.from_mpd( + url=audio_mpd_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + except KeyError: + self.log.warning(f" - Title has no {self.amanifest} stream, cannot get higher quality audio") + else: + tracks.add(audio_mpd.audios, warn_only=True) # expecting possible dupes, ignore + + need_uhd_audio = self.atmos + + if not self.amanifest and ((self.aquality == "UHD" and self.vquality != "UHD") or not self.aquality): + audios = defaultdict(list) + for audio in tracks.audios: + audios[audio.language].append(audio) + for lang in audios: + if not any((x.bitrate or 0) >= 640000 for x in audios[lang]): + need_uhd_audio = True + break + + if need_uhd_audio and (self.config.get("device") or {}).get(self.profile, None): + self.log.info("Getting audio from UHD manifest for potential higher bitrate or better codec") + temp_device = self.device + temp_device_token = self.device_token + temp_device_id = self.device_id + uhd_audio_manifest = None + + try: + if self.cdm.device.type == LocalDevice.Types.CHROME and self.quality < 2160: + self.log.info(f" + Switching to device to get UHD manifest") + self.register_device() + + uhd_audio_manifest = self.get_manifest( + title=title, + video_codec="H265", + bitrate_mode="CVBR+CBR", + quality="UHD", + hdr="DV", # Needed for 576kbps Atmos sometimes + ignore_errors=True + ) + except: + pass + + self.device = temp_device + self.device_token = temp_device_token + self.device_id = temp_device_id + + if not uhd_audio_manifest: + self.log.warning(f" - Unable to get UHD manifests, skipping") + elif not (chosen_uhd_audio_manifest := self.choose_manifest(uhd_audio_manifest, self.cdn)): + self.log.warning(f" - No UHD manifests available, skipping") + else: + uhd_audio_mpd_url = self.clean_mpd_url(chosen_uhd_audio_manifest["avUrlInfoList"][0]["url"], optimise=False) + self.log.debug(uhd_audio_mpd_url) + self.log.info(" + Downloading UHD manifest") + + try: + uhd_audio_mpd = Tracks([ + x for x in iter(Tracks.from_mpd( + url=uhd_audio_mpd_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + except KeyError: + self.log.warning(f" - Title has no UHD stream, cannot get higher quality audio") + else: + # replace the audio tracks with DV manifest version if atmos is present + if any(x for x in uhd_audio_mpd.audios if x.atmos): + tracks.audios = uhd_audio_mpd.audios + + for video in tracks.videos: + video.hdr10 = chosen_manifest["hdrFormat"] == "Hdr10" + video.dv = chosen_manifest["hdrFormat"] == "DolbyVision" + + for audio in tracks.audios: + audio.descriptive = audio.extra[1].get("audioTrackSubtype") == "descriptive" + # Amazon @lang is just the lang code, no dialect, @audioTrackId has it. + audio_track_id = audio.extra[1].get("audioTrackId") + if audio_track_id: + audio.language = Language.get(audio_track_id.split("_")[0]) # e.g. es-419_ec3_blabla + + for sub in manifest.get("subtitleUrls", []) + manifest.get("forcedNarratives", []): + tracks.add(TextTrack( + id_=sub.get( + "timedTextTrackId", + f"{sub['languageCode']}_{sub['type']}_{sub['subtype']}_{sub['index']}" + ), + source=self.ALIASES[0], + url=os.path.splitext(sub["url"])[0] + ".srt", # DFXP -> SRT forcefully seems to work fine + # metadata + codec="srt", # sub["format"].lower(), + language=sub["languageCode"], + #is_original_lang=title.original_lang and is_close_match(sub["languageCode"], [title.original_lang]), + forced="forced" in sub["displayName"], + sdh=sub["type"].lower() == "sdh" # TODO: what other sub types? cc? forced? + ), warn_only=True) # expecting possible dupes, ignore + + return tracks + + + def get_chapters(self, title: Title) -> list[MenuTrack]: + """Get chapters from Amazon's XRay Scenes API.""" + manifest = self.get_manifest( + title, + video_codec=self.vcodec, + bitrate_mode=self.bitrate, + quality=self.vquality, + hdr=self.range + ) + + if "xrayMetadata" in manifest: + xray_params = manifest["xrayMetadata"]["parameters"] + elif self.chapters_only: + xray_params = { + "pageId": "fullScreen", + "pageType": "xray", + "serviceToken": json.dumps({ + "consumptionType": "Streaming", + "deviceClass": "normal", + "playbackMode": "playback", + "vcid": manifest["returnedTitleRendition"]["contentId"], + }) + } + else: + return [] + + xray_params.update({ + "deviceID": self.device_id, + "deviceTypeID": self.config["device_types"]["browser"], # must be browser device type + "marketplaceID": self.region["marketplace_id"], + "gascEnabled": str(self.pv).lower(), + "decorationScheme": "none", + "version": "inception-v2", + "uxLocale": "en-US", + "featureScheme": "XRAY_WEB_2020_V1" + }) + + xray = self.session.get( + url=self.endpoints["xray"], + params=xray_params + ).json().get("page") + + if not xray: + return [] + + widgets = xray["sections"]["center"]["widgets"]["widgetList"] + + scenes = next((x for x in widgets if x["tabType"] == "scenesTab"), None) + if not scenes: + return [] + scenes = scenes["widgets"]["widgetList"][0]["items"]["itemList"] + + chapters = [] + + for scene in scenes: + chapter_title = scene["textMap"]["PRIMARY"] + match = re.search(r"(\d+\. |)(.+)", chapter_title) + if match: + chapter_title = match.group(2) + chapters.append(MenuTrack( + number=int(scene["id"].replace("/xray/scene/", "")), + title=chapter_title, + timecode=scene["textMap"]["TERTIARY"].replace("Starts at ", "") + )) + + return chapters + + def certificate(self, **_): + return self.config["certificate"] + + def license(self, challenge: bytes, title: Title, **_): + lic = self.session.post( + url=self.endpoints["licence"], + params={ + "asin": title.id, + "consumptionType": "Streaming", + "desiredResources": "PlayReadyLicense", + "deviceTypeID": self.device["device_type"], + "deviceID": self.device_id, + "firmware": 1, + "gascEnabled": str(self.pv).lower(), #Prime Video or not + "marketplaceID": self.region["marketplace_id"], + "resourceUsage": "ImmediateConsumption", + "videoMaterialType": "Feature", + "operatingSystemName": "Windows", + "operatingSystemVersion": "10.0", + "customerID": self.customer_id, + "deviceDrmOverride": "CENC", + "deviceStreamingTechnologyOverride": "DASH", + "deviceVideoQualityOverride": self.vquality, + "deviceHdrFormatsOverride": self.VIDEO_RANGE_MAP.get(self.range, "None"), + }, + headers={ + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": f"Bearer {self.device_token}" + }, + data={ + "playReadyChallenge": base64.b64encode(challenge.encode('utf-8')).decode('utf-8') # expects base64 + } + ).json() + if "errorsByResource" in lic: + print(lic) + error_code = lic["errorsByResource"]["playReadyLicense"] + if "errorCode" in error_code: + error_code = error_code["errorCode"] + elif "type" in error_code: + error_code = error_code["type"] + if error_code == "PRS.NoRights.AnonymizerIP": + raise self.log.exit(" - Amazon detected a Proxy/VPN and refused to return a license!") + message = lic["errorsByResource"]["playReadyLicense"]["message"] + raise self.log.exit(f" - Amazon reported an error during the License request: {message} [{error_code}]") + if "error" in lic: + error_code = lic["error"] + if "errorCode" in error_code: + error_code = error_code["errorCode"] + elif "type" in error_code: + error_code = error_code["type"] + if error_code == "PRS.NoRights.AnonymizerIP": + raise self.log.exit(" - Amazon detected a Proxy/VPN and refused to return a license!") + message = lic["error"]["message"] + raise self.log.exit(f" - Amazon reported an error during the License request: {message} [{error_code}]") + return lic["playReadyLicense"]["encodedLicenseResponse"] + + # Service specific functions + + def configure(self) -> None: + if len(self.title) > 10: + self.pv = True + + self.log.info("Getting Account Region") + self.region = self.get_region() + if not self.region: + raise self.log.exit(" - Failed to get Amazon Account region") + self.GEOFENCE.append(self.region["code"]) + self.log.info(f" + Region: {self.region['code']}") + + # endpoints must be prepared AFTER region data is retrieved + self.endpoints = self.prepare_endpoints(self.config["endpoints"], self.region) + + self.session.headers.update({ + "Origin": f"https://{self.region['base']}" + }) + + self.device = (self.config.get("device") or {}).get(self.profile, {}) + if (self.quality > 1080 or self.range != "SDR") and self.vcodec == "H265" and self.cdm.device.type == LocalDevice.Types.CHROME: + self.log.info(f"Using device to get UHD manifests") + self.register_device() + elif not self.device or self.cdm.device.type == LocalDevice.Types.CHROME or self.vquality == "SD": + # falling back to browser-based device ID + if not self.device: + self.log.warning( + "No Device information was provided for %s, using browser device...", + self.profile + ) + self.device_id = hashlib.sha224( + ("CustomerID" + self.session.headers["User-Agent"]).encode("utf-8") + ).hexdigest() + self.device = {"device_type": self.config["device_types"]["browser"]} + else: + self.register_device() + + def register_device(self) -> None: + self.device = (self.config.get("device") or {}).get(self.profile, {}) + device_cache_path = self.get_cache("device_tokens_{profile}_{hash}.json".format( + profile=self.profile, + hash=hashlib.md5(json.dumps(self.device).encode()).hexdigest()[0:6] + )) + self.device_token = self.DeviceRegistration( + device=self.device, + endpoints=self.endpoints, + log=self.log, + cache_path=device_cache_path, + session=self.session + ).bearer + self.device_id = self.device.get("device_serial") + if not self.device_id: + raise self.log.exit(f" - A device serial is required in the config, perhaps use: {os.urandom(8).hex()}") + + def get_region(self) -> dict: + domain_region = self.get_domain_region() + if not domain_region: + return {} + + region = self.config["regions"].get(domain_region) + if not region: + raise self.log.exit(f" - There's no region configuration data for the region: {domain_region}") + + region["code"] = domain_region + + if self.pv: + res = self.session.get("https://www.primevideo.com").text + match = re.search(r'ue_furl *= *([\'"])fls-(na|eu|fe)\.amazon\.[a-z.]+\1', res) + if match: + pv_region = match.group(2).lower() + else: + raise self.log.exit(" - Failed to get PrimeVideo region") + pv_region = {"na": "atv-ps"}.get(pv_region, f"atv-ps-{pv_region}") + region["base_manifest"] = f"{pv_region}.primevideo.com" + region["base"] = "www.primevideo.com" + + return region + + def get_domain_region(self): + """Get the region of the cookies from the domain.""" + tlds = [tldextract.extract(x.domain) for x in self.cookies if x.domain_specified] + tld = next((x.suffix for x in tlds if x.domain.lower() in ("amazon", "primevideo")), None) + if tld: + tld = tld.split(".")[-1] + return {"com": "us", "uk": "gb"}.get(tld, tld) + + def prepare_endpoint(self, name: str, uri: str, region: dict) -> str: + if name in ("browse", "playback", "licence", "xray"): + return f"https://{(region['base_manifest'])}{uri}" + if name in ("ontv", "devicelink", "details"): + if self.pv: + host = "www.primevideo.com" + else: + host = region["base"] + return f"https://{host}{uri}" + if name in ("codepair", "register", "token"): + return f"https://{self.config['regions']['us']['base_api']}{uri}" + raise ValueError(f"Unknown endpoint: {name}") + + def prepare_endpoints(self, endpoints: dict, region: dict) -> dict: + return {k: self.prepare_endpoint(k, v, region) for k, v in endpoints.items()} + + def choose_manifest(self, manifest: dict, cdn=None): + """Get manifest URL for the title based on CDN weight (or specified CDN).""" + if cdn: + cdn = cdn.lower() + manifest = next((x for x in manifest["audioVideoUrls"]["avCdnUrlSets"] if x["cdn"].lower() == cdn), {}) + if not manifest: + raise self.log.exit(f" - There isn't any DASH manifests available on the CDN \"{cdn}\" for this title") + else: + manifest = next((x for x in sorted([x for x in manifest["audioVideoUrls"]["avCdnUrlSets"]], key=lambda x: int(x["cdnWeightsRank"]))), {}) + + return manifest + + def get_manifest( + self, title: Title, video_codec: str, bitrate_mode: str, quality: str, hdr=None, + ignore_errors: bool = False + ) -> dict: + res = self.session.get( + url=self.endpoints["playback"], + params={ + "asin": title.id, + "consumptionType": "Streaming", + "desiredResources": ",".join([ + "PlaybackUrls", + "AudioVideoUrls", + "CatalogMetadata", + "ForcedNarratives", + "SubtitlePresets", + "SubtitleUrls", + "TransitionTimecodes", + "TrickplayUrls", + "CuepointPlaylist", + "XRayMetadata", + "PlaybackSettings", + ]), + "deviceID": self.device_id, + "deviceTypeID": self.device["device_type"], + "firmware": 1, + "gascEnabled": str(self.pv).lower(), + "marketplaceID": self.region["marketplace_id"], + "resourceUsage": "CacheResources", + "videoMaterialType": "Feature", + "playerType": "html5", + "clientId": self.client_id, + **({ + "operatingSystemName": "Linux" if quality == "SD" else "Windows", + "operatingSystemVersion": "unknown" if quality == "SD" else "10.0", + } if not self.device_token else {}), + "deviceDrmOverride": "CENC", + "deviceStreamingTechnologyOverride": "DASH", + "deviceProtocolOverride": "Https", + "deviceVideoCodecOverride": video_codec, + "deviceBitrateAdaptationsOverride": bitrate_mode.replace("+", ","), + "deviceVideoQualityOverride": quality, + "deviceHdrFormatsOverride": self.VIDEO_RANGE_MAP.get(hdr, "None"), + "supportedDRMKeyScheme": "DUAL_KEY", # ? + "liveManifestType": "live,accumulating", # ? + "titleDecorationScheme": "primary-content", + "subtitleFormat": "TTMLv2", + "languageFeature": "MLFv2", # ? + "uxLocale": "en_US", + "xrayDeviceClass": "normal", + "xrayPlaybackMode": "playback", + "xrayToken": "XRAY_WEB_2020_V1", + "playbackSettingsFormatVersion": "1.0.0", + "playerAttributes": json.dumps({"frameRate": "HFR"}), + # possibly old/unused/does nothing: + "audioTrackId": "all", + }, + headers={ + "Authorization": f"Bearer {self.device_token}" if self.device_token else None, + }, + ) + try: + manifest = res.json() + except json.JSONDecodeError: + if ignore_errors: + return {} + + raise self.log.exit(" - Amazon didn't return JSON data when obtaining the Playback Manifest.") + + if "error" in manifest: + if ignore_errors: + return {} + raise self.log.exit(" - Amazon reported an error when obtaining the Playback Manifest.") + + # Commented out as we move the rights exception check elsewhere + # if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: + # if ignore_errors: + # return {} + # raise self.log.exit(" - The profile used does not have the rights to this title.") + + # Below checks ignore NoRights errors + + if ( + manifest.get("errorsByResource", {}).get("PlaybackUrls") and + manifest["errorsByResource"]["PlaybackUrls"].get("errorCode") != "PRS.NoRights.NotOwned" + ): + if ignore_errors: + return {} + error = manifest["errorsByResource"]["PlaybackUrls"] + raise self.log.exit(f" - Amazon had an error with the Playback Urls: {error['message']} [{error['errorCode']}]") + + if ( + manifest.get("errorsByResource", {}).get("AudioVideoUrls") and + manifest["errorsByResource"]["AudioVideoUrls"].get("errorCode") != "PRS.NoRights.NotOwned" + ): + if ignore_errors: + return {} + error = manifest["errorsByResource"]["AudioVideoUrls"] + raise self.log.exit(f" - Amazon had an error with the A/V Urls: {error['message']} [{error['errorCode']}]") + + return manifest + + @staticmethod + def get_original_language(manifest): + """Get a title's original language from manifest data.""" + try: + return next( + x["language"].replace("_", "-") + for x in manifest["catalogMetadata"]["playback"]["audioTracks"] + if x["isOriginalLanguage"] + ) + except (KeyError, StopIteration): + pass + + if "defaultAudioTrackId" in manifest.get("playbackUrls", {}): + try: + return manifest["playbackUrls"]["defaultAudioTrackId"].split("_")[0] + except IndexError: + pass + + try: + return sorted( + manifest["audioVideoUrls"]["audioTrackMetadata"], + key=lambda x: x["index"] + )[0]["languageCode"] + except (KeyError, IndexError): + pass + + return None + + @staticmethod + def clean_mpd_url(mpd_url, optimise=True): + """Clean up an Amazon MPD manifest url.""" + if optimise: + return mpd_url.replace("~", "") + "?encoding=segmentBase" + else: + if match := re.match(r"(https?://.*/)d.?/.*~/(.*)", mpd_url): + print(f"returned: {''.join(match.groups())}") + return "".join(match.groups()) + elif match := re.match(r"(https?://.*/)d.?/.*\$.*?/(.*)", mpd_url): + print(f"returned: {''.join(match.groups())}") + return "".join(match.groups()) + raise ValueError("Unable to parse MPD URL") + + def get_best_quality(self, title): + """ + Choose the best quality manifest from CBR / CVBR + """ + + track_list = [] + bitrates = [self.orig_bitrate] + + if self.vcodec != "H265": + bitrates = self.orig_bitrate.split('+') + + for bitrate in bitrates: + manifest = self.get_manifest( + title, + video_codec=self.vcodec, + bitrate_mode=bitrate, + quality=self.vquality, + hdr=self.range, + ignore_errors=False + ) + + if not manifest: + self.log.warning(f"Skipping {bitrate} manifest due to error") + continue + + # return three empty objects if a rightsException error exists to correlate to manifest, chosen_manifest, tracks + if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: + return None, None, None + + self.customer_id = manifest["returnedTitleRendition"]["selectedEntitlement"]["grantedByCustomerId"] + + default_url_set = manifest["playbackUrls"]["urlSets"][manifest["playbackUrls"]["defaultUrlSetId"]] + encoding_version = default_url_set["urls"]["manifest"]["encodingVersion"] + self.log.info(f" + Detected encodingVersion={encoding_version}") + + chosen_manifest = self.choose_manifest(manifest, self.cdn) + + if not chosen_manifest: + self.log.warning(f"No {bitrate} DASH manifests available") + continue + + + mpd_url = self.clean_mpd_url(chosen_manifest["avUrlInfoList"][0]["url"], optimise=False) + self.log.debug(mpd_url) + self.log.info(f" + Downloading {bitrate} MPD") + + tracks = Tracks([ + x for x in iter(Tracks.from_mpd( + url=mpd_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + + for video in tracks.videos: + video.note = bitrate + + max_size = max(tracks.videos, key=lambda x: int(x.size or 0)).size + + track_list.append({ + 'bitrate': bitrate, + 'max_size': max_size, + 'manifest': manifest, + 'chosen_manifest': chosen_manifest, + 'tracks': tracks + }) + + best_quality = max(track_list, key=lambda x: x['max_size']) + + if len(self.bitrate.split('+')) > 1: + self.bitrate = best_quality['bitrate'] + self.log.info("Selected video manifest bitrate: %s", best_quality['bitrate']) + + return best_quality['manifest'], best_quality['chosen_manifest'], best_quality['tracks'] + + # Service specific classes + + class DeviceRegistration: + + def __init__(self, device: dict, endpoints: dict, cache_path: Path, session: requests.Session, log: Logger): + self.session = session + self.device = device + self.endpoints = endpoints + self.cache_path = cache_path + self.log = log + + self.device = {k: str(v) if not isinstance(v, str) else v for k, v in self.device.items()} + + self.bearer = None + if os.path.isfile(self.cache_path): + with open(self.cache_path, encoding="utf-8") as fd: + cache = jsonpickle.decode(fd.read()) + #self.device["device_serial"] = cache["device_serial"] + if cache.get("expires_in", 0) > int(time.time()): + # not expired, lets use + self.log.info(" + Using cached device bearer") + self.bearer = cache["access_token"] + else: + # expired, refresh + self.log.info("Cached device bearer expired, refreshing...") + refreshed_tokens = self.refresh(self.device, cache["refresh_token"]) + refreshed_tokens["refresh_token"] = cache["refresh_token"] + # expires_in seems to be in minutes, create a unix timestamp and add the minutes in seconds + refreshed_tokens["expires_in"] = int(time.time()) + int(refreshed_tokens["expires_in"]) + with open(self.cache_path, "w", encoding="utf-8") as fd: + fd.write(jsonpickle.encode(refreshed_tokens)) + self.bearer = refreshed_tokens["access_token"] + else: + self.log.info(" + Registering new device bearer") + self.bearer = self.register(self.device) + + def register(self, device: dict) -> dict: + """ + Register device to the account + :param device: Device data to register + :return: Device bearer tokens + """ + # OnTV csrf + csrf_token = self.get_csrf_token() + + # Code pair + code_pair = self.get_code_pair(device) + + # Device link + response = self.session.post( + url=self.endpoints["devicelink"], + headers={ + "Accept": "*/*", + "Accept-Language": "en-US,en;q=0.9,es-US;q=0.8,es;q=0.7", # needed? + "Content-Type": "application/x-www-form-urlencoded", + "Referer": self.endpoints["ontv"] + }, + params=urlencode({ + # any reason it urlencodes here? requests can take a param dict... + "ref_": "atv_set_rd_reg", + "publicCode": code_pair["public_code"], # public code pair + "token": csrf_token # csrf token + }) + ) + if response.status_code != 200: + raise self.log.exit(f"Unexpected response with the codeBasedLinking request: {response.text} [{response.status_code}]") + + # Register + response = self.session.post( + url=self.endpoints["register"], + headers={ + "Content-Type": "application/json", + "Accept-Language": "en-US" + }, + json={ + "auth_data": { + "code_pair": code_pair + }, + "registration_data": device, + "requested_token_type": ["bearer"], + "requested_extensions": ["device_info", "customer_info"] + }, + cookies=None # for some reason, may fail if cookies are present. Odd. + ) + if response.status_code != 200: + raise self.log.exit(f"Unable to register: {response.text} [{response.status_code}]") + bearer = response.json()["response"]["success"]["tokens"]["bearer"] + bearer["expires_in"] = int(time.time()) + int(bearer["expires_in"]) + + # Cache bearer + os.makedirs(os.path.dirname(self.cache_path), exist_ok=True) + with open(self.cache_path, "w", encoding="utf-8") as fd: + fd.write(jsonpickle.encode(bearer)) + + return bearer["access_token"] + + def refresh(self, device: dict, refresh_token: str) -> dict: + response = self.session.post( + url=self.endpoints["token"], + json={ + "app_name": device["app_name"], + "app_version": device["app_version"], + "source_token_type": "refresh_token", + "source_token": refresh_token, + "requested_token_type": "access_token" + } + ).json() + if "error" in response: + self.cache_path.unlink(missing_ok=True) # Remove the cached device as its tokens have expired + raise self.log.exit( + f"Failed to refresh device token: {response['error_description']} [{response['error']}]" + ) + if response["token_type"] != "bearer": + raise self.log.exit("Unexpected returned refreshed token type") + return response + + def get_csrf_token(self) -> str: + """ + On the amazon website, you need a token that is in the html page, + this token is used to register the device + :return: OnTV Page's CSRF Token + """ + res = self.session.get(self.endpoints["ontv"]) + response = res.text + if 'input type="hidden" name="appAction" value="SIGNIN"' in response: + raise self.log.exit( + "Cookies are signed out, cannot get ontv CSRF token. " + f"Expecting profile to have cookies for: {self.endpoints['ontv']}" + ) + for match in re.finditer(r"", response): + prop = json.loads(match.group(1)) + prop = prop.get("props", {}).get("codeEntry", {}).get("token") + if prop: + return prop + raise self.log.exit("Unable to get ontv CSRF token") + + def get_code_pair(self, device: dict) -> dict: + """ + Getting code pairs based on the device that you are using + :return: public and private code pairs + """ + res = self.session.post( + url=self.endpoints["codepair"], + headers={ + "Content-Type": "application/json", + "Accept-Language": "en-US" + }, + json={"code_data": device} + ).json() + if "error" in res: + raise self.log.exit(f"Unable to get code pair: {res['error_description']} [{res['error']}]") + return res diff --git a/binaries/N_m3u8DL-RE-samplefile.txt b/binaries/N_m3u8DL-RE-samplefile.txt deleted file mode 100644 index ccbed25..0000000 --- a/binaries/N_m3u8DL-RE-samplefile.txt +++ /dev/null @@ -1 +0,0 @@ -N_m3u8DL-RE.exe http://avodsls3ww-s.akamaihd.net/ondemand/iad_2/c5a2/7992/6e31/4ed5-8011-893c8d4e98a6/0bc9f599-85c7-450d-b829-b69fb27d4bd6.ism/manifest --thread-count 96 --log-level ERROR --write-meta-json False --http-request-timeout 8 \ No newline at end of file diff --git a/binaries/N_m3u8DL-RE.exe b/binaries/N_m3u8DL-RE.exe deleted file mode 100644 index ca7e57b..0000000 Binary files a/binaries/N_m3u8DL-RE.exe and /dev/null differ diff --git a/binaries/XstreamDL-CLI.zip b/binaries/XstreamDL-CLI.zip deleted file mode 100644 index d306890..0000000 Binary files a/binaries/XstreamDL-CLI.zip and /dev/null differ diff --git a/binaries/aria2c.exe b/binaries/aria2c.exe index 5004e10..7de7a06 100644 Binary files a/binaries/aria2c.exe and b/binaries/aria2c.exe differ diff --git a/binaries/curl.exe b/binaries/curl.exe index b98410d..b937210 100644 Binary files a/binaries/curl.exe and b/binaries/curl.exe differ diff --git a/binaries/mkvmerge.exe b/binaries/mkvmerge.exe index feb5a11..cd8d4ba 100644 Binary files a/binaries/mkvmerge.exe and b/binaries/mkvmerge.exe differ diff --git a/binaries/mp4box.exe b/binaries/mp4box.exe deleted file mode 100644 index 31a9fcb..0000000 Binary files a/binaries/mp4box.exe and /dev/null differ diff --git a/binaries/mp4decrypt.exe b/binaries/mp4decrypt.exe index af51068..92307bd 100644 Binary files a/binaries/mp4decrypt.exe and b/binaries/mp4decrypt.exe differ diff --git a/binaries/mp4decrypt_1.exe b/binaries/mp4decrypt_1.exe deleted file mode 100644 index 4956c22..0000000 Binary files a/binaries/mp4decrypt_1.exe and /dev/null differ diff --git a/binaries/mux_atmos.txt b/binaries/mux_atmos.txt deleted file mode 100644 index 2c67b35..0000000 --- a/binaries/mux_atmos.txt +++ /dev/null @@ -1 +0,0 @@ -ffmpeg -i correct_file.eac3 -map 0 -c:a copy correct_file.mp4 \ No newline at end of file diff --git a/binaries/packager-old.exe b/binaries/packager-old.exe deleted file mode 100644 index 743ad08..0000000 Binary files a/binaries/packager-old.exe and /dev/null differ diff --git a/binaries/packager.exe b/binaries/packager.exe index d35fd8c..743ad08 100644 Binary files a/binaries/packager.exe and b/binaries/packager.exe differ diff --git a/binary.txt b/binary.txt deleted file mode 100644 index 6a02f5a..0000000 --- a/binary.txt +++ /dev/null @@ -1,23 +0,0 @@ -dl -al en -sl en --keys -q 2160 --cdm hisense_smarttv_he55a7000euwts_sl3000 -r HDR --selected -w S05E08-S05E24 AMZN -b CBR -vq UHD 0IQZZIJ6W6TT2CXPT6ZOZYX396 - - ---include-data-files=/path/to/scan=folder_name=**/*.txt ---include-data-files=/path/to/file/*.txt=folder_name/some.txt ---include-data-files="./vinetrimmer/services/*.py"=vinetrimmer/services/ - ---onefile --> if this flag then figure out how to set the directories to NOT TEMP folder - -python -m nuitka --onefile --assume-yes-for-downloads --windows-console-mode=disable --show-progress --standalone --output-dir=dist --static-libpython=no vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer --include-data-dir=./binaries/=binaries --include-data-dir=./scripts/=scripts -python -m nuitka --onefile --standalone --output-dir=dist vinetrimmer1.py --include-data-dir=./vinetrimmer/services/=vinetrimmer/services --include-data-dir=./vinetrimmer/config/=vinetrimmer/config/ --include-data-dir=./vinetrimmer/config/Services/=vinetrimmer/config/Services/ --include-data-dir=./scripts/=scripts -python -m nuitka --onefile --standalone --windows-console-mode=attach --output-dir=dist vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer/ --include-data-dir=./vinetrimmer/services/*.py=vinetrimmer/services/=**/*.py --include-data-dir=./vinetrimmer/config/=vinetrimmer/config/ --include-data-dir=./vinetrimmer/config/Services/=vinetrimmer/config/Services/ --include-data-dir=./scripts/=scripts/ -python -m nuitka --onefile --standalone --windows-console-mode=attach --output-dir=dist vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer/ --include-data-files=./vinetrimmer/services/*.py=vinetrimmer/services/ --include-data-dir=./vinetrimmer/config/=vinetrimmer/config/ --include-data-dir=./vinetrimmer/config/Services/=vinetrimmer/config/Services/ --include-data-dir=./scripts/=scripts/ -python -m nuitka --mode=standalone --output-dir=dist --windows-console-mode=force vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer/ --include-data-files="./vinetrimmer/services/*.py"=vinetrimmer/services/ --include-data-dir=./vinetrimmer/config/=vinetrimmer/config/ --include-data-dir=./vinetrimmer/config/Services/=vinetrimmer/config/Services/ --include-data-dir=./scripts/=scripts/ -python -m nuitka --onefile --follow-imports --output-dir=dist --windows-console-mode=force vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer/ --include-data-files="./vinetrimmer/services/*.py"=vinetrimmer/services/ --include-data-dir=./vinetrimmer/config/=vinetrimmer/config/ --include-data-dir=./vinetrimmer/config/Services/=vinetrimmer/config/Services/ --include-data-dir=./scripts/=scripts/ --include-data-files="./vinetrimmer/config/*.py"=vinetrimmer/config/ -python -m nuitka --onefile --follow-imports --output-dir=dist --standalone --clang --windows-console-mode=force --show-memory vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer/ --include-data-files="./vinetrimmer/services/*.py"=vinetrimmer/services/ --include-data-dir=./vinetrimmer/config/=vinetrimmer/config/ --include-data-dir=./vinetrimmer/config/Services/=vinetrimmer/config/Services/ --include-data-dir=./scripts/=scripts/ --include-data-files="./vinetrimmer/config/*.py"=vinetrimmer/config/ - -python -m nuitka --follow-imports --output-dir=dist --standalone --clang --windows-console-mode=force --show-memory vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer/ --include-data-files="./vinetrimmer/services/*.py"=vinetrimmer/services/ --include-data-dir=./vinetrimmer/config/=vinetrimmer/config/ --include-data-dir=./vinetrimmer/config/Services/=vinetrimmer/config/Services/ --include-data-dir=./scripts/=scripts/ --include-data-files="./vinetrimmer/config/*.py"=vinetrimmer/config/ -python -m nuitka --onefile --follow-imports --output-dir=dist --standalone --clang --windows-console-mode=force --show-memory vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer/ --include-data-dir=./vinetrimmer/config/=vinetrimmer/config/ --include-data-dir=./vinetrimmer/config/Services/=vinetrimmer/config/Services/ --include-data-dir=./scripts/=scripts/ --include-data-files="./vinetrimmer/config/*.py"=vinetrimmer/config/ -nuitka --output-dir=dist --standalone --windows-console-mode=force vinetrimmer1.py --include-data-dir=./vinetrimmer/=vinetrimmer/ - - -nuitka --onefile --output-dir=dist --windows-console-mode=force vt.py --include-data-dir=./vinetrimmer/=vinetrimmer/ \ No newline at end of file diff --git a/commands.txt b/commands.txt index 0567e9c..56c624b 100644 --- a/commands.txt +++ b/commands.txt @@ -1,36 +1,42 @@ https://www.primevideo.com/region/eu/storefront -poetry run vt dl -al en -sl en -r HDR --list AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 -poetry run vt dl -al en -sl en --list AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 -poetry run vt dl -al en --selected --keys AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 -poetry run vt dl -al en --selected AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 -poetry run vt dl -q 2160 -al en -sl en --list AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 -poetry run vt dl -q 2160 -al en -sl en --keys AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 --bitrate CVBR+CBR -poetry run vt dl -al en -sl en --selected AMZN -b CBR https://www.primevideo.com/detail/0I1GTXP9ZKTV7AAD7E1LCWJCUX/ +poetry run vt dl -al en -sl en -r HDR --list Amazon 0SGEGC629FCXQ5DJ9ORNE42PXK +poetry run vt dl -al en -sl en --list Amazon 0SGEGC629FCXQ5DJ9ORNE42PXK +poetry run vt dl -al en --selected --keys Amazon 0SGEGC629FCXQ5DJ9ORNE42PXK +poetry run vt dl -al en --selected Amazon 0SGEGC629FCXQ5DJ9ORNE42PXK -poetry run vt dl -al en -sl en -q 2160 --keys -r HDR AMZN -b CBR 0OSAJR8S2YWRSQCYS4J8MEGEXI -poetry run vt dl -al en -sl en -q 2160 -r HDR --selected -w S05E08-S05E24 AMZN -b CBR 0IQZZIJ6W6TT2CXPT6ZOZYX396 +poetry run vt dl -q 2160 -al en -sl en -r HDR --list Amazon 0H7LY5ZKKBM1MIW0244WE9O2C4 +poetry run vt dl -q 2160 -al en -sl en --selected --keys Amazon 0H7LY5ZKKBM1MIW0244WE9O2C4 -python vinetrimmer1.py dl -al en -sl en -q 2160 -r HDR --selected -w S05E09-S05E24 AMZN -b CBR 0IQZZIJ6W6TT2CXPT6ZOZYX396 -poetry run vt dl -al en -sl en --selected -q 2160 -r HDR -w S01E18-S01E25 AMZN -b CBR --ism 0IQZZIJ6W6TT2CXPT6ZOZYX396 +poetry run vt dl -q 2160 -al en -sl en --keys --no-cache --vcodec H265 --selected AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 --bitrate CBR +poetry run vt dl -q 2160 -al en -sl en --keys --no-cache --debug --vcodec H265 --selected AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 --bitrate CBR -Atmos audio download AMZN to fix --> poetry run vt dl -al en -aa -sl en --selected --debug -w S01E01 -A AMZN -b CBR --ism 0HAQAA7JM43QWX0H6GUD3IOF70 http://ABHIRCQAAAAAAAAMCX3W7WLVKL54A.s3-bom-ww.cf.smooth.row.aiv-cdn.net/e5b0/2fe1/032c/4fae-b896-aca9d8bef3d4/170b36b1-856d-4c69-bbf6-feb6c979185a.ism/manifest -poetry run vt dl -al en -sl en -r HDR -w S01E01 --list -q 2160 AMZN https://www.primevideo.com/detail/0HU52DR3U1R0FGI3KSUL00XYY7 +poetry run vt dl -al en -sl en -r HDR -w S01E01 --list --debug -q 2160 Amazon https://www.primevideo.com/detail/0HU52DR3U1R0FGI3KSUL00XYY7/ https://www.primevideo.com/detail/0HU52DR3U1R0FGI3KSUL00XYY7/ https://ABAKS6NAAAAAAAAMBIBDKKUP3ONNU.s3-iad-2.cf.smooth.row.aiv-cdn.net/357a/1bb0/c1f3/4a6b-b709-d6f2edf5b709/15eab8ec-d8ac-4c23-96fc-f5d89f459829.ism/manifest + http://ABHIRCQAAAAAAAAMHLTVNGLHRCITQ.s3-bom-ww.cf.smooth.row.aiv-cdn.net/e7ab/7c49/9743/4e53-ab5c-6d15516ecf15/52bf7e61-51cd-4e5d-bd68-834706f17789.ism/manifest https://www.primevideo.com/region/eu/detail/0KYRVT4JDB957NXZO72E2MIFW5/ + + https://m-5884s3.ll.smooth.row.aiv-cdn.net/iad_2/3572/bbdc/73b4/404d-a100-802b1d9de4c6/862e2506-c20e-4ba7-bacc-d6b4775e7b62.ism/manifest +Max show poetry run vt dl -al en -sl en -w S01E01 Max https://play.max.com/show/c8ea8e19-cae7-4683-9b62-cdbbed744784 + UHD -poetry run vt dl -al en -sl en --keys Max https://play.max.com/show/5756c2bf-36f8-4890-b1f9-ef168f1d8e9c +poetry run vt dl -al en -sl en -v H265 --keys Max https://play.max.com/show/5756c2bf-36f8-4890-b1f9-ef168f1d8e9c + poetry run vt dl -al en -sl en -w S02E05-S02E10 --selected --proxy http://192.168.0.99:9766 Max -poetry run vt dl -al en -sl en --list -w S01E01 --proxy http://192.168.0.99:9766 Max +poetry run vt dl -al en -sl en -v H265 --list -w S01E01 --proxy http://192.168.0.99:9766 Max poetry run vt dl -al all --selected --proxy http://192.168.0.99:9766 --debug -w S01E01 ATVP umc.cmc.7gvn6fekgfpq5fc72pgi1c47o + poetry run vt dl -al en -sl en --selected --debug -q 720 --proxy http://192.168.0.99:9766 -w S01E01 ATVP umc.cmc.1nfdfd5zlk05fo1bwwetzldy3 -poetry run vt dl -al en -sl en --selected --proxy http://192.168.0.99:9766 -w S01E01 ATVP umc.cmc.1nfdfd5zlk05fo1bwwetzldy3 \ No newline at end of file + + +poetry run vt dl -al en -sl en --cdm hisense_smarttv_hu50a6100uw_sl3000 --selected --proxy http://192.168.0.99:9766 --keys -w S01E02 ATVP umc.cmc.1nfdfd5zlk05fo1bwwetzldy3 +poetry run vt dl -al en -sl en --cdm hisense_smarttv_hu50a6100uw_sl3000 --selected --proxy http://192.168.0.99:9766 --keys -q 2160 ATVP umc.cmc.apzybj6eqf6pzccd97kev7bs \ No newline at end of file diff --git a/fix.txt b/fix.txt deleted file mode 100644 index f06071a..0000000 --- a/fix.txt +++ /dev/null @@ -1,54 +0,0 @@ -D:\PlayReady-Amazon-Tool-main>poetry run vt dl -al en -sl en --selected --keys --cdm hisense_smarttv_he55a7000euwts_sl3000 AMZN -vq UHD -b CVBR+CBR https://www.primevideo.com/detail/0I1GTXP9ZKTV7AAD7E1LCWJCUX/ -2025-02-07 22:26:57 [I] vt : vinetrimmer - Widevine DRM downloader and decrypter -2025-02-07 22:26:57 [I] vt : [Root Config] : D:\PlayReady-Amazon-Tool-main\vinetrimmer\vinetrimmer.yml -2025-02-07 22:26:57 [I] vt : [Service Configs] : D:\PlayReady-Amazon-Tool-main\vinetrimmer\Services -2025-02-07 22:26:57 [I] vt : [Cookies] : D:\PlayReady-Amazon-Tool-main\vinetrimmer\Cookies -2025-02-07 22:26:57 [I] vt : [CDM Devices] : D:\PlayReady-Amazon-Tool-main\vinetrimmer\devices -2025-02-07 22:26:57 [I] vt : [Cache] : D:\PlayReady-Amazon-Tool-main\vinetrimmer\Cache -2025-02-07 22:26:57 [I] vt : [Logs] : D:\PlayReady-Amazon-Tool-main\vinetrimmer\Logs -2025-02-07 22:26:57 [I] vt : [Temp Files] : D:\PlayReady-Amazon-Tool-main\Temp -2025-02-07 22:26:57 [I] vt : [Downloads] : D:\PlayReady-Amazon-Tool-main\Downloads -2025-02-07 22:26:57 [I] dl : + 1 Local Vault -2025-02-07 22:26:57 [I] dl : + 0 Remote Vaults -2025-02-07 22:26:57 [I] dl : + Loaded Device: hisense_smarttv_he55a7000euwts_sl3000 (L3000) -2025-02-07 22:26:57 [I] AMZN : Getting Account Region -2025-02-07 22:26:59 [I] AMZN : + Region: us -2025-02-07 22:26:59 [I] AMZN : + Using cached device bearer -2025-02-07 22:26:59 [I] AMZN : Retrieving Titles -2025-02-07 22:27:00 [I] Titles : Title: I Was Not Ready Da -2025-02-07 22:27:00 [I] AMZN : Getting tracks for I Was Not Ready Da (2020) [amzn1.dv.gti.30baee18-aa4c-1fc2-72cc-6e11d5e627d9] -2025-02-07 22:27:01 [I] AMZN : + Detected encodingVersion=2 -2025-02-07 22:27:01 [I] AMZN : + Downloading CVBR MPD -2025-02-07 22:27:02 [I] AMZN : + Detected encodingVersion=2 -2025-02-07 22:27:02 [I] AMZN : + Downloading CBR MPD -Traceback (most recent call last): - File "", line 1, in - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 1161, in __call__ - return self.main(*args, **kwargs) - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 1082, in main - rv = self.invoke(ctx) - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 1443, in invoke - return ctx.invoke(self.callback, **ctx.params) - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 788, in invoke - return __callback(*args, **kwargs) - File "D:\PlayReady-Amazon-Tool-main\vinetrimmer\vinetrimmer.py", line 72, in main - dl() - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 1161, in __call__ - return self.main(*args, **kwargs) - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 1082, in main - rv = self.invoke(ctx) - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 1697, in invoke - return _process_result(sub_ctx.command.invoke(sub_ctx)) - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 1666, in _process_result - value = ctx.invoke(self._result_callback, value, **ctx.params) - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\core.py", line 788, in invoke - return __callback(*args, **kwargs) - File "D:\PlayReady-Amazon-Tool-main\.venv\lib\site-packages\click\decorators.py", line 33, in new_func - return f(get_current_context(), *args, **kwargs) - File "D:\PlayReady-Amazon-Tool-main\vinetrimmer\commands\dl.py", line 309, in result - title.tracks.add(service.get_tracks(title), warn_only=True) - File "D:\PlayReady-Amazon-Tool-main\vinetrimmer\services\amazon.py", line 321, in get_tracks - manifest, chosen_manifest, tracks = self.get_best_quality(title) - File "D:\PlayReady-Amazon-Tool-main\vinetrimmer\services\amazon.py", line 1051, in get_best_quality - best_quality = max(track_list, key=lambda x: x['max_size']) -TypeError: '>' not supported between instances of 'NoneType' and 'NoneType' \ No newline at end of file diff --git a/install.bat b/install.bat index 4a8fcab..d64fe24 100644 --- a/install.bat +++ b/install.bat @@ -1,6 +1,5 @@ @echo off -python -m pip install poetry==1.8.5 +python -m pip install poetry poetry config virtualenvs.in-project true -poetry lock --no-update poetry install pause \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 6a28fa8..5466c55 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "altgraph" @@ -13,25 +13,24 @@ files = [ [[package]] name = "anyio" -version = "4.5.2" +version = "4.0.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.5.2-py3-none-any.whl", hash = "sha256:c011ee36bc1e8ba40e5a81cb9df91925c218fe9b778554e0b56a21e1b5d4716f"}, - {file = "anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b"}, + {file = "anyio-4.0.0-py3-none-any.whl", hash = "sha256:cfdb2b588b9fc25ede96d8db56ed50848b0b649dca3dd1df0b11f683bb9e0b5f"}, + {file = "anyio-4.0.0.tar.gz", hash = "sha256:f7ed51751b2c2add651e5747c891b47e26d2a21be5d32d9311dfe9692f3e5d7a"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] -trio = ["trio (>=0.26.1)"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.22)"] [[package]] name = "appdirs" @@ -236,137 +235,76 @@ files = [ [package.dependencies] cffi = ">=1.0.0" -[[package]] -name = "build" -version = "1.2.2.post1" -description = "A simple, correct Python build frontend" -optional = false -python-versions = ">=3.8" -files = [ - {file = "build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"}, - {file = "build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "os_name == \"nt\""} -importlib-metadata = {version = ">=4.6", markers = "python_full_version < \"3.10.2\""} -packaging = ">=19.1" -pyproject_hooks = "*" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} - -[package.extras] -docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"] -test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"] -typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"] -uv = ["uv (>=0.1.18)"] -virtualenv = ["virtualenv (>=20.0.35)"] - -[[package]] -name = "cachecontrol" -version = "0.14.2" -description = "httplib2 caching for requests" -optional = false -python-versions = ">=3.8" -files = [ - {file = "cachecontrol-0.14.2-py3-none-any.whl", hash = "sha256:ebad2091bf12d0d200dfc2464330db638c5deb41d546f6d7aca079e87290f3b0"}, - {file = "cachecontrol-0.14.2.tar.gz", hash = "sha256:7d47d19f866409b98ff6025b6a0fca8e4c791fb31abbd95f622093894ce903a2"}, -] - -[package.dependencies] -filelock = {version = ">=3.8.0", optional = true, markers = "extra == \"filecache\""} -msgpack = ">=0.5.2,<2.0.0" -requests = ">=2.16.0" - -[package.extras] -dev = ["CacheControl[filecache,redis]", "build", "cherrypy", "codespell[tomli]", "furo", "mypy", "pytest", "pytest-cov", "ruff", "sphinx", "sphinx-copybutton", "tox", "types-redis", "types-requests"] -filecache = ["filelock (>=3.8.0)"] -redis = ["redis (>=2.10.5)"] - [[package]] name = "certifi" -version = "2024.12.14" +version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, - {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, ] [[package]] name = "cffi" -version = "1.17.1" +version = "1.16.0" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, - {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] [package.dependencies] @@ -374,129 +312,112 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.4.1" +version = "3.3.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7" +python-versions = ">=3.7.0" files = [ - {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, - {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, - {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, + {file = "charset-normalizer-3.3.0.tar.gz", hash = "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-win32.whl", hash = "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-win32.whl", hash = "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-win32.whl", hash = "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-win32.whl", hash = "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-win32.whl", hash = "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-win32.whl", hash = "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884"}, + {file = "charset_normalizer-3.3.0-py3-none-any.whl", hash = "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2"}, ] -[[package]] -name = "cleo" -version = "2.1.0" -description = "Cleo allows you to create beautiful and testable command-line interfaces." -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "cleo-2.1.0-py3-none-any.whl", hash = "sha256:4a31bd4dd45695a64ee3c4758f583f134267c2bc518d8ae9a29cf237d009b07e"}, - {file = "cleo-2.1.0.tar.gz", hash = "sha256:0b2c880b5d13660a7ea651001fb4acb527696c01f15c9ee650f377aa543fd523"}, -] - -[package.dependencies] -crashtest = ">=0.4.1,<0.5.0" -rapidfuzz = ">=3.0.0,<4.0.0" - [[package]] name = "click" -version = "8.1.8" +version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, - {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -532,24 +453,17 @@ cron = ["capturer (>=2.4)"] [[package]] name = "construct" -version = "2.8.8" -description = "A powerful declarative parser/builder for binary data" +version = "2.10.70" +description = "A powerful declarative symmetric parser/builder for binary data" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "construct-2.8.8.tar.gz", hash = "sha256:1b84b8147f6fd15bcf64b737c3e8ac5100811ad80c830cb4b2545140511c4157"}, + {file = "construct-2.10.70-py3-none-any.whl", hash = "sha256:c80be81ef595a1a821ec69dc16099550ed22197615f4320b57cc9ce2a672cb30"}, + {file = "construct-2.10.70.tar.gz", hash = "sha256:4d2472f9684731e58cc9c56c463be63baa1447d674e0d66aeb5627b22f512c29"}, ] -[[package]] -name = "crashtest" -version = "0.4.1" -description = "Manage Python errors with ease" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "crashtest-0.4.1-py3-none-any.whl", hash = "sha256:8d23eac5fa660409f57472e3851dab7ac18aba459a8d19cbbba86d3d5aecd2a5"}, - {file = "crashtest-0.4.1.tar.gz", hash = "sha256:80d7b1f316ebfbd429f648076d6275c877ba30ba48979de4191714a75266f0ce"}, -] +[package.extras] +extras = ["arrow", "cloudpickle", "cryptography", "lz4", "numpy", "ruamel.yaml"] [[package]] name = "crccheck" @@ -613,21 +527,18 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "cssutils" -version = "2.11.1" +version = "2.9.0" description = "A CSS Cascading Style Sheets library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "cssutils-2.11.1-py3-none-any.whl", hash = "sha256:a67bfdfdff4f3867fab43698ec4897c1a828eca5973f4073321b3bccaf1199b1"}, - {file = "cssutils-2.11.1.tar.gz", hash = "sha256:0563a76513b6af6eebbe788c3bf3d01c920e46b3f90c8416738c5cfc773ff8e2"}, + {file = "cssutils-2.9.0-py3-none-any.whl", hash = "sha256:f8b013169e281c0c6083207366c5005f5dd4549055f7aba840384fb06a78745c"}, + {file = "cssutils-2.9.0.tar.gz", hash = "sha256:89477b3d17d790e97b9fb4def708767061055795aae6f7c82ae32e967c9be4cd"}, ] -[package.dependencies] -more-itertools = "*" - [package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["cssselect", "importlib-resources", "jaraco.test (>=5.1)", "lxml", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["cssselect", "importlib-resources", "jaraco.test (>=5.1)", "lxml", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [[package]] name = "decorator" @@ -640,104 +551,6 @@ files = [ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] -[[package]] -name = "distlib" -version = "0.3.9" -description = "Distribution utilities" -optional = false -python-versions = "*" -files = [ - {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, - {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, -] - -[[package]] -name = "dulwich" -version = "0.21.7" -description = "Python Git Library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d4c0110798099bb7d36a110090f2688050703065448895c4f53ade808d889dd3"}, - {file = "dulwich-0.21.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2bc12697f0918bee324c18836053644035362bb3983dc1b210318f2fed1d7132"}, - {file = "dulwich-0.21.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:471305af74790827fcbafe330fc2e8bdcee4fb56ca1177c8c481b1c8f806c4a4"}, - {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54c9d0e845be26f65f954dff13a1cd3f2b9739820c19064257b8fd7435ab263"}, - {file = "dulwich-0.21.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12d61334a575474e707614f2e93d6ed4cdae9eb47214f9277076d9e5615171d3"}, - {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e274cebaf345f0b1e3b70197f2651de92b652386b68020cfd3bf61bc30f6eaaa"}, - {file = "dulwich-0.21.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:817822f970e196e757ae01281ecbf21369383285b9f4a83496312204cf889b8c"}, - {file = "dulwich-0.21.7-cp310-cp310-win32.whl", hash = "sha256:7836da3f4110ce684dcd53489015fb7fa94ed33c5276e3318b8b1cbcb5b71e08"}, - {file = "dulwich-0.21.7-cp310-cp310-win_amd64.whl", hash = "sha256:4a043b90958cec866b4edc6aef5fe3c2c96a664d0b357e1682a46f6c477273c4"}, - {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ce8db196e79c1f381469410d26fb1d8b89c6b87a4e7f00ff418c22a35121405c"}, - {file = "dulwich-0.21.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:62bfb26bdce869cd40be443dfd93143caea7089b165d2dcc33de40f6ac9d812a"}, - {file = "dulwich-0.21.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c01a735b9a171dcb634a97a3cec1b174cfbfa8e840156870384b633da0460f18"}, - {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa4d14767cf7a49c9231c2e52cb2a3e90d0c83f843eb6a2ca2b5d81d254cf6b9"}, - {file = "dulwich-0.21.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bca4b86e96d6ef18c5bc39828ea349efb5be2f9b1f6ac9863f90589bac1084d"}, - {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a7b5624b02ef808cdc62dabd47eb10cd4ac15e8ac6df9e2e88b6ac6b40133673"}, - {file = "dulwich-0.21.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c3a539b4696a42fbdb7412cb7b66a4d4d332761299d3613d90a642923c7560e1"}, - {file = "dulwich-0.21.7-cp311-cp311-win32.whl", hash = "sha256:675a612ce913081beb0f37b286891e795d905691dfccfb9bf73721dca6757cde"}, - {file = "dulwich-0.21.7-cp311-cp311-win_amd64.whl", hash = "sha256:460ba74bdb19f8d498786ae7776745875059b1178066208c0fd509792d7f7bfc"}, - {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4c51058ec4c0b45dc5189225b9e0c671b96ca9713c1daf71d622c13b0ab07681"}, - {file = "dulwich-0.21.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4bc4c5366eaf26dda3fdffe160a3b515666ed27c2419f1d483da285ac1411de0"}, - {file = "dulwich-0.21.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a0650ec77d89cb947e3e4bbd4841c96f74e52b4650830112c3057a8ca891dc2f"}, - {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f18f0a311fb7734b033a3101292b932158cade54b74d1c44db519e42825e5a2"}, - {file = "dulwich-0.21.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c589468e5c0cd84e97eb7ec209ab005a2cb69399e8c5861c3edfe38989ac3a8"}, - {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d62446797163317a397a10080c6397ffaaca51a7804c0120b334f8165736c56a"}, - {file = "dulwich-0.21.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e84cc606b1f581733df4350ca4070e6a8b30be3662bbb81a590b177d0c996c91"}, - {file = "dulwich-0.21.7-cp312-cp312-win32.whl", hash = "sha256:c3d1685f320907a52c40fd5890627945c51f3a5fa4bcfe10edb24fec79caadec"}, - {file = "dulwich-0.21.7-cp312-cp312-win_amd64.whl", hash = "sha256:6bd69921fdd813b7469a3c77bc75c1783cc1d8d72ab15a406598e5a3ba1a1503"}, - {file = "dulwich-0.21.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7d8ab29c660125db52106775caa1f8f7f77a69ed1fe8bc4b42bdf115731a25bf"}, - {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0d2e4485b98695bf95350ce9d38b1bb0aaac2c34ad00a0df789aa33c934469b"}, - {file = "dulwich-0.21.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e138d516baa6b5bafbe8f030eccc544d0d486d6819b82387fc0e285e62ef5261"}, - {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f34bf9b9fa9308376263fd9ac43143c7c09da9bc75037bb75c6c2423a151b92c"}, - {file = "dulwich-0.21.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e2c66888207b71cd1daa2acb06d3984a6bc13787b837397a64117aa9fc5936a"}, - {file = "dulwich-0.21.7-cp37-cp37m-win32.whl", hash = "sha256:10893105c6566fc95bc2a67b61df7cc1e8f9126d02a1df6a8b2b82eb59db8ab9"}, - {file = "dulwich-0.21.7-cp37-cp37m-win_amd64.whl", hash = "sha256:460b3849d5c3d3818a80743b4f7a0094c893c559f678e56a02fff570b49a644a"}, - {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:74700e4c7d532877355743336c36f51b414d01e92ba7d304c4f8d9a5946dbc81"}, - {file = "dulwich-0.21.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c92e72c43c9e9e936b01a57167e0ea77d3fd2d82416edf9489faa87278a1cdf7"}, - {file = "dulwich-0.21.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d097e963eb6b9fa53266146471531ad9c6765bf390849230311514546ed64db2"}, - {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:808e8b9cc0aa9ac74870b49db4f9f39a52fb61694573f84b9c0613c928d4caf8"}, - {file = "dulwich-0.21.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1957b65f96e36c301e419d7adaadcff47647c30eb072468901bb683b1000bc5"}, - {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4b09bc3a64fb70132ec14326ecbe6e0555381108caff3496898962c4136a48c6"}, - {file = "dulwich-0.21.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5882e70b74ac3c736a42d3fdd4f5f2e6570637f59ad5d3e684760290b58f041"}, - {file = "dulwich-0.21.7-cp38-cp38-win32.whl", hash = "sha256:29bb5c1d70eba155ded41ed8a62be2f72edbb3c77b08f65b89c03976292f6d1b"}, - {file = "dulwich-0.21.7-cp38-cp38-win_amd64.whl", hash = "sha256:25c3ab8fb2e201ad2031ddd32e4c68b7c03cb34b24a5ff477b7a7dcef86372f5"}, - {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8929c37986c83deb4eb500c766ee28b6670285b512402647ee02a857320e377c"}, - {file = "dulwich-0.21.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cc1e11be527ac06316539b57a7688bcb1b6a3e53933bc2f844397bc50734e9ae"}, - {file = "dulwich-0.21.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fc3078a1ba04c588fabb0969d3530efd5cd1ce2cf248eefb6baf7cbc15fc285"}, - {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dcbd29ba30ba2c5bfbab07a61a5f20095541d5ac66d813056c122244df4ac0"}, - {file = "dulwich-0.21.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8869fc8ec3dda743e03d06d698ad489b3705775fe62825e00fa95aa158097fc0"}, - {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d96ca5e0dde49376fbcb44f10eddb6c30284a87bd03bb577c59bb0a1f63903fa"}, - {file = "dulwich-0.21.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0064363bd5e814359657ae32517fa8001e8573d9d040bd997908d488ab886ed"}, - {file = "dulwich-0.21.7-cp39-cp39-win32.whl", hash = "sha256:869eb7be48243e695673b07905d18b73d1054a85e1f6e298fe63ba2843bb2ca1"}, - {file = "dulwich-0.21.7-cp39-cp39-win_amd64.whl", hash = "sha256:404b8edeb3c3a86c47c0a498699fc064c93fa1f8bab2ffe919e8ab03eafaaad3"}, - {file = "dulwich-0.21.7-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e598d743c6c0548ebcd2baf94aa9c8bfacb787ea671eeeb5828cfbd7d56b552f"}, - {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a2d76c96426e791556836ef43542b639def81be4f1d6d4322cd886c115eae1"}, - {file = "dulwich-0.21.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6c88acb60a1f4d31bd6d13bfba465853b3df940ee4a0f2a3d6c7a0778c705b7"}, - {file = "dulwich-0.21.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ecd315847dea406a4decfa39d388a2521e4e31acde3bd9c2609c989e817c6d62"}, - {file = "dulwich-0.21.7-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d05d3c781bc74e2c2a2a8f4e4e2ed693540fbe88e6ac36df81deac574a6dad99"}, - {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6de6f8de4a453fdbae8062a6faa652255d22a3d8bce0cd6d2d6701305c75f2b3"}, - {file = "dulwich-0.21.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e25953c7acbbe4e19650d0225af1c0c0e6882f8bddd2056f75c1cc2b109b88ad"}, - {file = "dulwich-0.21.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4637cbd8ed1012f67e1068aaed19fcc8b649bcf3e9e26649826a303298c89b9d"}, - {file = "dulwich-0.21.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:858842b30ad6486aacaa607d60bab9c9a29e7c59dc2d9cb77ae5a94053878c08"}, - {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:739b191f61e1c4ce18ac7d520e7a7cbda00e182c3489552408237200ce8411ad"}, - {file = "dulwich-0.21.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:274c18ec3599a92a9b67abaf110e4f181a4f779ee1aaab9e23a72e89d71b2bd9"}, - {file = "dulwich-0.21.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2590e9b431efa94fc356ae33b38f5e64f1834ec3a94a6ac3a64283b206d07aa3"}, - {file = "dulwich-0.21.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed60d1f610ef6437586f7768254c2a93820ccbd4cfdac7d182cf2d6e615969bb"}, - {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8278835e168dd097089f9e53088c7a69c6ca0841aef580d9603eafe9aea8c358"}, - {file = "dulwich-0.21.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffc27fb063f740712e02b4d2f826aee8bbed737ed799962fef625e2ce56e2d29"}, - {file = "dulwich-0.21.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:61e3451bd3d3844f2dca53f131982553be4d1b1e1ebd9db701843dd76c4dba31"}, - {file = "dulwich-0.21.7.tar.gz", hash = "sha256:a9e9c66833cea580c3ac12927e4b9711985d76afca98da971405d414de60e968"}, -] - -[package.dependencies] -urllib3 = ">=1.25" - -[package.extras] -fastimport = ["fastimport"] -https = ["urllib3 (>=1.24.1)"] -paramiko = ["paramiko"] -pgp = ["gpg"] - [[package]] name = "ecpy" version = "1.2.5" @@ -751,47 +564,33 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.1.3" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, ] [package.extras] test = ["pytest (>=6)"] -[[package]] -name = "fastjsonschema" -version = "2.21.1" -description = "Fastest Python implementation of JSON schema" -optional = false -python-versions = "*" -files = [ - {file = "fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"}, - {file = "fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4"}, -] - -[package.extras] -devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] - [[package]] name = "filelock" -version = "3.16.1" +version = "3.12.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, - {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, + {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, + {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] -typing = ["typing-extensions (>=4.12.2)"] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] +typing = ["typing-extensions (>=4.7.1)"] [[package]] name = "flake8" @@ -880,72 +679,13 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve [[package]] name = "idna" -version = "3.10" +version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.6" +python-versions = ">=3.5" files = [ - {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, - {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, -] - -[package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] - -[[package]] -name = "importlib-metadata" -version = "8.5.0" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, - {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, -] - -[package.dependencies] -zipp = ">=3.20" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] -type = ["pytest-mypy"] - -[[package]] -name = "importlib-resources" -version = "6.4.5" -description = "Read resources from Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, - {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, -] - -[package.dependencies] -zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] -type = ["pytest-mypy"] - -[[package]] -name = "installer" -version = "0.7.0" -description = "A library for installing Python wheels." -optional = false -python-versions = ">=3.7" -files = [ - {file = "installer-0.7.0-py3-none-any.whl", hash = "sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53"}, - {file = "installer-0.7.0.tar.gz", hash = "sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631"}, + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] [[package]] @@ -975,50 +715,20 @@ six = "*" [[package]] name = "isort" -version = "5.13.2" +version = "5.12.0" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, ] [package.extras] -colors = ["colorama (>=0.4.6)"] - -[[package]] -name = "jaraco-classes" -version = "3.4.0" -description = "Utility functions for Python class constructs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, - {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, -] - -[package.dependencies] -more-itertools = "*" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "jeepney" -version = "0.8.0" -description = "Low-level, pure Python DBus protocol wrapper." -optional = false -python-versions = ">=3.7" -files = [ - {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, - {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, -] - -[package.extras] -test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] -trio = ["async_generator", "trio"] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "jsonpickle" @@ -1036,173 +746,141 @@ docs = ["jaraco.packaging (>=3.2)", "rst.linker (>=1.9)", "sphinx"] testing = ["ecdsa", "enum34", "feedparser", "jsonlib", "numpy", "pandas", "pymongo", "pytest (>=3.5,!=3.7.3)", "pytest-black-multipy", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-flake8 (<1.1.0)", "pytest-flake8 (>=1.1.1)", "scikit-learn", "sqlalchemy"] testing-libs = ["simplejson", "ujson", "yajl"] -[[package]] -name = "keyring" -version = "24.3.1" -description = "Store and access your passwords safely." -optional = false -python-versions = ">=3.8" -files = [ - {file = "keyring-24.3.1-py3-none-any.whl", hash = "sha256:df38a4d7419a6a60fea5cef1e45a948a3e8430dd12ad88b0f423c5c143906218"}, - {file = "keyring-24.3.1.tar.gz", hash = "sha256:c3327b6ffafc0e8befbdb597cacdb4928ffe5c1212f7645f186e6d9957a898db"}, -] - -[package.dependencies] -importlib-metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} -importlib-resources = {version = "*", markers = "python_version < \"3.9\""} -"jaraco.classes" = "*" -jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} -pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} -SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} - -[package.extras] -completion = ["shtab (>=1.1.0)"] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - [[package]] name = "langcodes" -version = "3.4.1" -description = "Tools for labeling human languages with IETF language tags" +version = "3.2.1" +description = "Labels and compares human languages in a standardized way" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "langcodes-3.4.1-py3-none-any.whl", hash = "sha256:68f686fc3d358f222674ecf697ddcee3ace3c2fe325083ecad2543fd28a20e77"}, - {file = "langcodes-3.4.1.tar.gz", hash = "sha256:a24879fed238013ac3af2424b9d1124e38b4a38b2044fd297c8ff38e5912e718"}, + {file = "langcodes-3.2.1.tar.gz", hash = "sha256:779a6da5036f87b6b56c180b2782ab111ddd6aa9157670a9b918402b0e07cd93"}, ] [package.dependencies] -language-data = ">=1.2" +language_data = {version = ">=1.0.1", optional = true, markers = "extra == \"data\""} [package.extras] -build = ["build", "twine"] -test = ["pytest", "pytest-cov"] +data = ["language_data (>=1.0.1)"] [[package]] name = "language-data" -version = "1.3.0" -description = "Supplementary data about languages used by the langcodes module" +version = "1.0.1" +description = "Supplementary data about languages used by the langcodes module." optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "language_data-1.3.0-py3-none-any.whl", hash = "sha256:e2ee943551b5ae5f89cd0e801d1fc3835bb0ef5b7e9c3a4e8e17b2b214548fbf"}, - {file = "language_data-1.3.0.tar.gz", hash = "sha256:7600ef8aa39555145d06c89f0c324bf7dab834ea0b0a439d8243762e3ebad7ec"}, + {file = "language_data-1.0.1.tar.gz", hash = "sha256:63563be4bd30336f1bc1d9b883f9daa53c0d503abf05d2f478ac9242eb588a7a"}, ] [package.dependencies] -marisa-trie = ">=1.1.0" - -[package.extras] -build = ["build", "twine"] -test = ["pytest", "pytest-cov"] +marisa-trie = "*" [[package]] name = "lxml" -version = "4.9.4" +version = "4.9.3" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ - {file = "lxml-4.9.4-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e214025e23db238805a600f1f37bf9f9a15413c7bf5f9d6ae194f84980c78722"}, - {file = "lxml-4.9.4-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec53a09aee61d45e7dbe7e91252ff0491b6b5fee3d85b2d45b173d8ab453efc1"}, - {file = "lxml-4.9.4-cp27-cp27m-win32.whl", hash = "sha256:7d1d6c9e74c70ddf524e3c09d9dc0522aba9370708c2cb58680ea40174800013"}, - {file = "lxml-4.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:cb53669442895763e61df5c995f0e8361b61662f26c1b04ee82899c2789c8f69"}, - {file = "lxml-4.9.4-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:647bfe88b1997d7ae8d45dabc7c868d8cb0c8412a6e730a7651050b8c7289cf2"}, - {file = "lxml-4.9.4-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4d973729ce04784906a19108054e1fd476bc85279a403ea1a72fdb051c76fa48"}, - {file = "lxml-4.9.4-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:056a17eaaf3da87a05523472ae84246f87ac2f29a53306466c22e60282e54ff8"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:aaa5c173a26960fe67daa69aa93d6d6a1cd714a6eb13802d4e4bd1d24a530644"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:647459b23594f370c1c01768edaa0ba0959afc39caeeb793b43158bb9bb6a663"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:bdd9abccd0927673cffe601d2c6cdad1c9321bf3437a2f507d6b037ef91ea307"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:00e91573183ad273e242db5585b52670eddf92bacad095ce25c1e682da14ed91"}, - {file = "lxml-4.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a602ed9bd2c7d85bd58592c28e101bd9ff9c718fbde06545a70945ffd5d11868"}, - {file = "lxml-4.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:de362ac8bc962408ad8fae28f3967ce1a262b5d63ab8cefb42662566737f1dc7"}, - {file = "lxml-4.9.4-cp310-cp310-win32.whl", hash = "sha256:33714fcf5af4ff7e70a49731a7cc8fd9ce910b9ac194f66eaa18c3cc0a4c02be"}, - {file = "lxml-4.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:d3caa09e613ece43ac292fbed513a4bce170681a447d25ffcbc1b647d45a39c5"}, - {file = "lxml-4.9.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:359a8b09d712df27849e0bcb62c6a3404e780b274b0b7e4c39a88826d1926c28"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:43498ea734ccdfb92e1886dfedaebeb81178a241d39a79d5351ba2b671bff2b2"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4855161013dfb2b762e02b3f4d4a21cc7c6aec13c69e3bffbf5022b3e708dd97"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c71b5b860c5215fdbaa56f715bc218e45a98477f816b46cfde4a84d25b13274e"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9a2b5915c333e4364367140443b59f09feae42184459b913f0f41b9fed55794a"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d82411dbf4d3127b6cde7da0f9373e37ad3a43e89ef374965465928f01c2b979"}, - {file = "lxml-4.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:273473d34462ae6e97c0f4e517bd1bf9588aa67a1d47d93f760a1282640e24ac"}, - {file = "lxml-4.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:389d2b2e543b27962990ab529ac6720c3dded588cc6d0f6557eec153305a3622"}, - {file = "lxml-4.9.4-cp311-cp311-win32.whl", hash = "sha256:8aecb5a7f6f7f8fe9cac0bcadd39efaca8bbf8d1bf242e9f175cbe4c925116c3"}, - {file = "lxml-4.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:c7721a3ef41591341388bb2265395ce522aba52f969d33dacd822da8f018aff8"}, - {file = "lxml-4.9.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:dbcb2dc07308453db428a95a4d03259bd8caea97d7f0776842299f2d00c72fc8"}, - {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:01bf1df1db327e748dcb152d17389cf6d0a8c5d533ef9bab781e9d5037619229"}, - {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e8f9f93a23634cfafbad6e46ad7d09e0f4a25a2400e4a64b1b7b7c0fbaa06d9d"}, - {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3f3f00a9061605725df1816f5713d10cd94636347ed651abdbc75828df302b20"}, - {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:953dd5481bd6252bd480d6ec431f61d7d87fdcbbb71b0d2bdcfc6ae00bb6fb10"}, - {file = "lxml-4.9.4-cp312-cp312-win32.whl", hash = "sha256:266f655d1baff9c47b52f529b5f6bec33f66042f65f7c56adde3fcf2ed62ae8b"}, - {file = "lxml-4.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:f1faee2a831fe249e1bae9cbc68d3cd8a30f7e37851deee4d7962b17c410dd56"}, - {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:23d891e5bdc12e2e506e7d225d6aa929e0a0368c9916c1fddefab88166e98b20"}, - {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e96a1788f24d03e8d61679f9881a883ecdf9c445a38f9ae3f3f193ab6c591c66"}, - {file = "lxml-4.9.4-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:5557461f83bb7cc718bc9ee1f7156d50e31747e5b38d79cf40f79ab1447afd2d"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:fdb325b7fba1e2c40b9b1db407f85642e32404131c08480dd652110fc908561b"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d74d4a3c4b8f7a1f676cedf8e84bcc57705a6d7925e6daef7a1e54ae543a197"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ac7674d1638df129d9cb4503d20ffc3922bd463c865ef3cb412f2c926108e9a4"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:ddd92e18b783aeb86ad2132d84a4b795fc5ec612e3545c1b687e7747e66e2b53"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bd9ac6e44f2db368ef8986f3989a4cad3de4cd55dbdda536e253000c801bcc7"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bc354b1393dce46026ab13075f77b30e40b61b1a53e852e99d3cc5dd1af4bc85"}, - {file = "lxml-4.9.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f836f39678cb47c9541f04d8ed4545719dc31ad850bf1832d6b4171e30d65d23"}, - {file = "lxml-4.9.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:9c131447768ed7bc05a02553d939e7f0e807e533441901dd504e217b76307745"}, - {file = "lxml-4.9.4-cp36-cp36m-win32.whl", hash = "sha256:bafa65e3acae612a7799ada439bd202403414ebe23f52e5b17f6ffc2eb98c2be"}, - {file = "lxml-4.9.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6197c3f3c0b960ad033b9b7d611db11285bb461fc6b802c1dd50d04ad715c225"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:7b378847a09d6bd46047f5f3599cdc64fcb4cc5a5a2dd0a2af610361fbe77b16"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:1343df4e2e6e51182aad12162b23b0a4b3fd77f17527a78c53f0f23573663545"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6dbdacf5752fbd78ccdb434698230c4f0f95df7dd956d5f205b5ed6911a1367c"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:506becdf2ecaebaf7f7995f776394fcc8bd8a78022772de66677c84fb02dd33d"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca8e44b5ba3edb682ea4e6185b49661fc22b230cf811b9c13963c9f982d1d964"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9d9d5726474cbbef279fd709008f91a49c4f758bec9c062dfbba88eab00e3ff9"}, - {file = "lxml-4.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:bbdd69e20fe2943b51e2841fc1e6a3c1de460d630f65bde12452d8c97209464d"}, - {file = "lxml-4.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8671622256a0859f5089cbe0ce4693c2af407bc053dcc99aadff7f5310b4aa02"}, - {file = "lxml-4.9.4-cp37-cp37m-win32.whl", hash = "sha256:dd4fda67f5faaef4f9ee5383435048ee3e11ad996901225ad7615bc92245bc8e"}, - {file = "lxml-4.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6bee9c2e501d835f91460b2c904bc359f8433e96799f5c2ff20feebd9bb1e590"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:1f10f250430a4caf84115b1e0f23f3615566ca2369d1962f82bef40dd99cd81a"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b505f2bbff50d261176e67be24e8909e54b5d9d08b12d4946344066d66b3e43"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1449f9451cd53e0fd0a7ec2ff5ede4686add13ac7a7bfa6988ff6d75cff3ebe2"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4ece9cca4cd1c8ba889bfa67eae7f21d0d1a2e715b4d5045395113361e8c533d"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59bb5979f9941c61e907ee571732219fa4774d5a18f3fa5ff2df963f5dfaa6bc"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b1980dbcaad634fe78e710c8587383e6e3f61dbe146bcbfd13a9c8ab2d7b1192"}, - {file = "lxml-4.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9ae6c3363261021144121427b1552b29e7b59de9d6a75bf51e03bc072efb3c37"}, - {file = "lxml-4.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bcee502c649fa6351b44bb014b98c09cb00982a475a1912a9881ca28ab4f9cd9"}, - {file = "lxml-4.9.4-cp38-cp38-win32.whl", hash = "sha256:a8edae5253efa75c2fc79a90068fe540b197d1c7ab5803b800fccfe240eed33c"}, - {file = "lxml-4.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:701847a7aaefef121c5c0d855b2affa5f9bd45196ef00266724a80e439220e46"}, - {file = "lxml-4.9.4-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:f610d980e3fccf4394ab3806de6065682982f3d27c12d4ce3ee46a8183d64a6a"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:aa9b5abd07f71b081a33115d9758ef6077924082055005808f68feccb27616bd"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:365005e8b0718ea6d64b374423e870648ab47c3a905356ab6e5a5ff03962b9a9"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:16b9ec51cc2feab009e800f2c6327338d6ee4e752c76e95a35c4465e80390ccd"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:a905affe76f1802edcac554e3ccf68188bea16546071d7583fb1b693f9cf756b"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd814847901df6e8de13ce69b84c31fc9b3fb591224d6762d0b256d510cbf382"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91bbf398ac8bb7d65a5a52127407c05f75a18d7015a270fdd94bbcb04e65d573"}, - {file = "lxml-4.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f99768232f036b4776ce419d3244a04fe83784bce871b16d2c2e984c7fcea847"}, - {file = "lxml-4.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bb5bd6212eb0edfd1e8f254585290ea1dadc3687dd8fd5e2fd9a87c31915cdab"}, - {file = "lxml-4.9.4-cp39-cp39-win32.whl", hash = "sha256:88f7c383071981c74ec1998ba9b437659e4fd02a3c4a4d3efc16774eb108d0ec"}, - {file = "lxml-4.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:936e8880cc00f839aa4173f94466a8406a96ddce814651075f95837316369899"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:f6c35b2f87c004270fa2e703b872fcc984d714d430b305145c39d53074e1ffe0"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:606d445feeb0856c2b424405236a01c71af7c97e5fe42fbc778634faef2b47e4"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a1bdcbebd4e13446a14de4dd1825f1e778e099f17f79718b4aeaf2403624b0f7"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0a08c89b23117049ba171bf51d2f9c5f3abf507d65d016d6e0fa2f37e18c0fc5"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:232fd30903d3123be4c435fb5159938c6225ee8607b635a4d3fca847003134ba"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:231142459d32779b209aa4b4d460b175cadd604fed856f25c1571a9d78114771"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:520486f27f1d4ce9654154b4494cf9307b495527f3a2908ad4cb48e4f7ed7ef7"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:562778586949be7e0d7435fcb24aca4810913771f845d99145a6cee64d5b67ca"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a9e7c6d89c77bb2770c9491d988f26a4b161d05c8ca58f63fb1f1b6b9a74be45"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:786d6b57026e7e04d184313c1359ac3d68002c33e4b1042ca58c362f1d09ff58"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95ae6c5a196e2f239150aa4a479967351df7f44800c93e5a975ec726fef005e2"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:9b556596c49fa1232b0fff4b0e69b9d4083a502e60e404b44341e2f8fb7187f5"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:cc02c06e9e320869d7d1bd323df6dd4281e78ac2e7f8526835d3d48c69060683"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:857d6565f9aa3464764c2cb6a2e3c2e75e1970e877c188f4aeae45954a314e0c"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c42ae7e010d7d6bc51875d768110c10e8a59494855c3d4c348b068f5fb81fdcd"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f10250bb190fb0742e3e1958dd5c100524c2cc5096c67c8da51233f7448dc137"}, - {file = "lxml-4.9.4.tar.gz", hash = "sha256:b1541e50b78e15fa06a2670157a1962ef06591d4c998b998047fff5e3236880e"}, + {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, + {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, + {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, + {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, + {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, + {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, + {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, + {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, + {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, + {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, + {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, + {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, + {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, + {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, + {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, + {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, + {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, + {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, + {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, + {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, + {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, + {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, + {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, + {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (==0.29.37)"] +source = ["Cython (>=0.29.35)"] [[package]] name = "m3u8" @@ -1234,87 +912,80 @@ altgraph = ">=0.17" [[package]] name = "marisa-trie" -version = "1.2.1" +version = "1.1.0" description = "Static memory-efficient and fast Trie-like structures for Python." optional = false python-versions = ">=3.7" files = [ - {file = "marisa_trie-1.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a2eb41d2f9114d8b7bd66772c237111e00d2bae2260824560eaa0a1e291ce9e8"}, - {file = "marisa_trie-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9e956e6a46f604b17d570901e66f5214fb6f658c21e5e7665deace236793cef6"}, - {file = "marisa_trie-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bd45142501300e7538b2e544905580918b67b1c82abed1275fe4c682c95635fa"}, - {file = "marisa_trie-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8443d116c612cfd1961fbf76769faf0561a46d8e317315dd13f9d9639ad500c"}, - {file = "marisa_trie-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:875a6248e60fbb48d947b574ffa4170f34981f9e579bde960d0f9a49ea393ecc"}, - {file = "marisa_trie-1.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:746a7c60a17fccd3cfcfd4326926f02ea4fcdfc25d513411a0c4fc8e4a1ca51f"}, - {file = "marisa_trie-1.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e70869737cc0e5bd903f620667da6c330d6737048d1f44db792a6af68a1d35be"}, - {file = "marisa_trie-1.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06b099dd743676dbcd8abd8465ceac8f6d97d8bfaabe2c83b965495523b4cef2"}, - {file = "marisa_trie-1.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d2a82eb21afdaf22b50d9b996472305c05ca67fc4ff5a026a220320c9c961db6"}, - {file = "marisa_trie-1.2.1-cp310-cp310-win32.whl", hash = "sha256:8951e7ce5d3167fbd085703b4cbb3f47948ed66826bef9a2173c379508776cf5"}, - {file = "marisa_trie-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:5685a14b3099b1422c4f59fa38b0bf4b5342ee6cc38ae57df9666a0b28eeaad3"}, - {file = "marisa_trie-1.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed3fb4ed7f2084597e862bcd56c56c5529e773729a426c083238682dba540e98"}, - {file = "marisa_trie-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fe69fb9ffb2767746181f7b3b29bbd3454d1d24717b5958e030494f3d3cddf3"}, - {file = "marisa_trie-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4728ed3ae372d1ea2cdbd5eaa27b8f20a10e415d1f9d153314831e67d963f281"}, - {file = "marisa_trie-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cf4f25cf895692b232f49aa5397af6aba78bb679fb917a05fce8d3cb1ee446d"}, - {file = "marisa_trie-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cca7f96236ffdbf49be4b2e42c132e3df05968ac424544034767650913524de"}, - {file = "marisa_trie-1.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7eb20bf0e8b55a58d2a9b518aabc4c18278787bdba476c551dd1c1ed109e509"}, - {file = "marisa_trie-1.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b1ec93f0d1ee6d7ab680a6d8ea1a08bf264636358e92692072170032dda652ba"}, - {file = "marisa_trie-1.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e2699255d7ac610dee26d4ae7bda5951d05c7d9123a22e1f7c6a6f1964e0a4e4"}, - {file = "marisa_trie-1.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c484410911182457a8a1a0249d0c09c01e2071b78a0a8538cd5f7fa45589b13a"}, - {file = "marisa_trie-1.2.1-cp311-cp311-win32.whl", hash = "sha256:ad548117744b2bcf0e3d97374608be0a92d18c2af13d98b728d37cd06248e571"}, - {file = "marisa_trie-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:436f62d27714970b9cdd3b3c41bdad046f260e62ebb0daa38125ef70536fc73b"}, - {file = "marisa_trie-1.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:638506eacf20ca503fff72221a7e66a6eadbf28d6a4a6f949fcf5b1701bb05ec"}, - {file = "marisa_trie-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de1665eaafefa48a308e4753786519888021740501a15461c77bdfd57638e6b4"}, - {file = "marisa_trie-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f713af9b8aa66a34cd3a78c7d150a560a75734713abe818a69021fd269e927fa"}, - {file = "marisa_trie-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2a7d00f53f4945320b551bccb826b3fb26948bde1a10d50bb9802fabb611b10"}, - {file = "marisa_trie-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98042040d1d6085792e8d0f74004fc0f5f9ca6091c298f593dd81a22a4643854"}, - {file = "marisa_trie-1.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6532615111eec2c79e711965ece0bc95adac1ff547a7fff5ffca525463116deb"}, - {file = "marisa_trie-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:20948e40ab2038e62b7000ca6b4a913bc16c91a2c2e6da501bd1f917eeb28d51"}, - {file = "marisa_trie-1.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66b23e5b35dd547f85bf98db7c749bc0ffc57916ade2534a6bbc32db9a4abc44"}, - {file = "marisa_trie-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6704adf0247d2dda42e876b793be40775dff46624309ad99bc7537098bee106d"}, - {file = "marisa_trie-1.2.1-cp312-cp312-win32.whl", hash = "sha256:3ad356442c2fea4c2a6f514738ddf213d23930f942299a2b2c05df464a00848a"}, - {file = "marisa_trie-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:f2806f75817392cedcacb24ac5d80b0350dde8d3861d67d045c1d9b109764114"}, - {file = "marisa_trie-1.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b5ea16e69bfda0ac028c921b58de1a4aaf83d43934892977368579cd3c0a2554"}, - {file = "marisa_trie-1.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9f627f4e41be710b6cb6ed54b0128b229ac9d50e2054d9cde3af0fef277c23cf"}, - {file = "marisa_trie-1.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5e649f3dc8ab5476732094f2828cc90cac3be7c79bc0c8318b6fda0c1d248db4"}, - {file = "marisa_trie-1.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46e528ee71808c961baf8c3ce1c46a8337ec7a96cc55389d11baafe5b632f8e9"}, - {file = "marisa_trie-1.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36aa4401a1180615f74d575571a6550081d84fc6461e9aefc0bb7b2427af098e"}, - {file = "marisa_trie-1.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce59bcd2cda9bb52b0e90cc7f36413cd86c3d0ce7224143447424aafb9f4aa48"}, - {file = "marisa_trie-1.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f4cd800704a5fc57e53c39c3a6b0c9b1519ebdbcb644ede3ee67a06eb542697d"}, - {file = "marisa_trie-1.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2428b495003c189695fb91ceeb499f9fcced3a2dce853e17fa475519433c67ff"}, - {file = "marisa_trie-1.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:735c363d9aaac82eaf516a28f7c6b95084c2e176d8231c87328dc80e112a9afa"}, - {file = "marisa_trie-1.2.1-cp313-cp313-win32.whl", hash = "sha256:eba6ca45500ca1a042466a0684aacc9838e7f20fe2605521ee19f2853062798f"}, - {file = "marisa_trie-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:aa7cd17e1c690ce96c538b2f4aae003d9a498e65067dd433c52dd069009951d4"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5e43891a37b0d7f618819fea14bd951289a0a8e3dd0da50c596139ca83ebb9b1"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6946100a43f933fad6bc458c502a59926d80b321d5ac1ed2ff9c56605360496f"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4177dc0bd1374e82be9b2ba4d0c2733b0a85b9d154ceeea83a5bee8c1e62fbf"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f35c2603a6be168088ed1db6ad1704b078aa8f39974c60888fbbced95dcadad4"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d659fda873d8dcb2c14c2c331de1dee21f5a902d7f2de7978b62c6431a8850ef"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:b0ef26733d3c836be79e812071e1a431ce1f807955a27a981ebb7993d95f842b"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:536ea19ce6a2ce61c57fed4123ecd10d18d77a0db45cd2741afff2b8b68f15b3"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-win32.whl", hash = "sha256:0ee6cf6a16d9c3d1c94e21c8e63c93d8b34bede170ca4e937e16e1c0700d399f"}, - {file = "marisa_trie-1.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7e7b1786e852e014d03e5f32dbd991f9a9eb223dd3fa9a2564108b807e4b7e1c"}, - {file = "marisa_trie-1.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:952af3a5859c3b20b15a00748c36e9eb8316eb2c70bd353ae1646da216322908"}, - {file = "marisa_trie-1.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24a81aa7566e4ec96fc4d934581fe26d62eac47fc02b35fa443a0bb718b471e8"}, - {file = "marisa_trie-1.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9c9b32b14651a6dcf9e8857d2df5d29d322a1ea8c0be5c8ffb88f9841c4ec62b"}, - {file = "marisa_trie-1.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ac170d20b97beb75059ba65d1ccad6b434d777c8992ab41ffabdade3b06dd74"}, - {file = "marisa_trie-1.2.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da4e4facb79614cc4653cfd859f398e4db4ca9ab26270ff12610e50ed7f1f6c6"}, - {file = "marisa_trie-1.2.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25688f34cac3bec01b4f655ffdd6c599a01f0bd596b4a79cf56c6f01a7df3560"}, - {file = "marisa_trie-1.2.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:1db3213b451bf058d558f6e619bceff09d1d130214448a207c55e1526e2773a1"}, - {file = "marisa_trie-1.2.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:d5648c6dcc5dc9200297fb779b1663b8a4467bda034a3c69bd9c32d8afb33b1d"}, - {file = "marisa_trie-1.2.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5bd39a4e1cc839a88acca2889d17ebc3f202a5039cd6059a13148ce75c8a6244"}, - {file = "marisa_trie-1.2.1-cp38-cp38-win32.whl", hash = "sha256:594f98491a96c7f1ffe13ce292cef1b4e63c028f0707effdea0f113364c1ae6c"}, - {file = "marisa_trie-1.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:5fe5a286f997848a410eebe1c28657506adaeb405220ee1e16cfcfd10deb37f2"}, - {file = "marisa_trie-1.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c0fe2ace0cb1806badbd1c551a8ec2f8d4cf97bf044313c082ef1acfe631ddca"}, - {file = "marisa_trie-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:67f0c2ec82c20a02c16fc9ba81dee2586ef20270127c470cb1054767aa8ba310"}, - {file = "marisa_trie-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a3c98613180cf1730e221933ff74b454008161b1a82597e41054127719964188"}, - {file = "marisa_trie-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:429858a0452a7bedcf67bc7bb34383d00f666c980cb75a31bcd31285fbdd4403"}, - {file = "marisa_trie-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2eacb84446543082ec50f2fb563f1a94c96804d4057b7da8ed815958d0cdfbe"}, - {file = "marisa_trie-1.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:852d7bcf14b0c63404de26e7c4c8d5d65ecaeca935e93794331bc4e2f213660b"}, - {file = "marisa_trie-1.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e58788004adda24c401d1751331618ed20c507ffc23bfd28d7c0661a1cf0ad16"}, - {file = "marisa_trie-1.2.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aefe0973cc4698e0907289dc0517ab0c7cdb13d588201932ff567d08a50b0e2e"}, - {file = "marisa_trie-1.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c50c861faad0a5c091bd763e0729f958c316e678dfa065d3984fbb9e4eacbcd"}, - {file = "marisa_trie-1.2.1-cp39-cp39-win32.whl", hash = "sha256:b1ce340da608530500ab4f963f12d6bfc8d8680900919a60dbdc9b78c02060a4"}, - {file = "marisa_trie-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:ce37d8ca462bb64cc13f529b9ed92f7b21fe8d1f1679b62e29f9cb7d0e888b49"}, - {file = "marisa_trie-1.2.1.tar.gz", hash = "sha256:3a27c408e2aefc03e0f1d25b2ff2afb85aac3568f6fa2ae2a53b57a2e87ce29d"}, + {file = "marisa-trie-1.1.0.tar.gz", hash = "sha256:5bf43ed0cf36af4578fe7b034cf95f532439766516680e4bd603723611ebd56b"}, + {file = "marisa_trie-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1b37ef1444083ab11e15d9150861874d8dd7be70c8899eccf1b986d37823a5"}, + {file = "marisa_trie-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:119366f9db9f53242439f69c3d49a3f1a3912970bc29b9af6ed9b6d0b7ef8c9e"}, + {file = "marisa_trie-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6964bfa23af502591094712e79886974a631d8047eb72cdf646babc62b03ae5e"}, + {file = "marisa_trie-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab8ec133daabb288e832d448fdff2e71756e7ba5ea7ff1b7b7645b010b2c23ac"}, + {file = "marisa_trie-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61a52a0e5ef404bfdcc2117cd39cb572595ff01f73f27feb5fc9e92889adbae0"}, + {file = "marisa_trie-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9ce60c2ed4f4138ef78e346d43b105185977c6be7bce0609b48bb14092110612"}, + {file = "marisa_trie-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3b90a422eb660bd111ffe54290bfbabf98a30fccfe8a594a512b3ba81fda8aa5"}, + {file = "marisa_trie-1.1.0-cp310-cp310-win32.whl", hash = "sha256:6b92cd77787aeb92fd815a5ad00d4828f528d30032c1314d5f17571afe125cbe"}, + {file = "marisa_trie-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:d415c11aada47f7f4afb818ce92e46c8f1b55611d325c09df7070088cfaa24bb"}, + {file = "marisa_trie-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:68a71ebb12498ad82e1579f41efe52c91839d92c0823a79389924057094c0a68"}, + {file = "marisa_trie-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1de6df9686175feb48f1e271a9252f6bf7ce1a4669a5bab3a97dffb8b11b13e6"}, + {file = "marisa_trie-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:789374ab88afe9e8ecfbd03a213f7b11fbefb3a8286c8fad88a2da0d7e5e0ef9"}, + {file = "marisa_trie-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f1b05f7dcde6ca2b460126519a37707fde53808b9e29e6d5b44de737262104"}, + {file = "marisa_trie-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:312e414001e5777506f459fa3032c3a5827e80a32babfd44ab528dd0fb824e61"}, + {file = "marisa_trie-1.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:571f68432d3dbf06b715cbb6aed1eed9898c149619045d65e6d82407d4eb4c9e"}, + {file = "marisa_trie-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1d98fe7da386c7f789526d8cf0b824b87fa1019e52619f8ad5e877912cc0f71"}, + {file = "marisa_trie-1.1.0-cp311-cp311-win32.whl", hash = "sha256:953400c8d7639349df9ef3f899f67c158852416a0470e7221fb06f19e3b1d0f6"}, + {file = "marisa_trie-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:c423e651daec5931371fa3d480fb5ac59164ed7dea968d8f51b1ba369bac4975"}, + {file = "marisa_trie-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9f4a37a17b9a551d1678b909c44841109b9979d12e72a9ed6e922a51f41889f1"}, + {file = "marisa_trie-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bbc118727474d710851db69d2762b4a3936ad1d2ffebb519c3f8f42a925fa118"}, + {file = "marisa_trie-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8c74557386eb62ce6526a9d0ad44410530e973feee5e0cabebf57b4d72696b2a"}, + {file = "marisa_trie-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4af7893ffc7099b68fd9d667fecc50d38e3e49405fcd6be97bc5ec72816ffa2"}, + {file = "marisa_trie-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:690eb9af9c0f4c677b74077843d0afafd08e543cdb3905b8a354aa0b0a2c06c3"}, + {file = "marisa_trie-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7e1771bedce1d9c37931c5efffac23aaed32f1364b99420673fa9417a0b5a6f1"}, + {file = "marisa_trie-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:38a64b1b4cbab19c23cfabed654c99e072af1c574f54b57ededd81357382d679"}, + {file = "marisa_trie-1.1.0-cp312-cp312-win32.whl", hash = "sha256:92cfb535174d711c3dbb3a9f3bbbd5abd180e778cd8ba2839a34565294c33190"}, + {file = "marisa_trie-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:9f0cd1d11f7f7022a044a32a59632f18af91ee31fa84ff98c914cb5b9fae449d"}, + {file = "marisa_trie-1.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1d95308e0453302706d5246935beb9e3255c20238a633d0637b3d345de428aa3"}, + {file = "marisa_trie-1.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dbff54cf950dccc8bded31ad130571330efd1d6849fbcc7825e62ac5063bd0a"}, + {file = "marisa_trie-1.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c14e494b28f78f806f5320f02b8625770d598bff0a4ea45f825f55257efcaf52"}, + {file = "marisa_trie-1.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2484e83b9c233b337f45bb09740a74aeb510081856cdd4b293b48b970c710c1d"}, + {file = "marisa_trie-1.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f661d79e5fef5c38ab41fd5a16c29f8bd9d46a0de6c407b88ebbf24c7637ac84"}, + {file = "marisa_trie-1.1.0-cp37-cp37m-win32.whl", hash = "sha256:5998b16395cefd76c52ce8cae35b837254ff097d3a357023f592218ff9d2112b"}, + {file = "marisa_trie-1.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:0b5d97515d9d65f237049ba01d385455fe5cc8dfb9c97b4a5b976382b9aff6c1"}, + {file = "marisa_trie-1.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4407e7ec82cdb501015188f1895bbdcac1a5ecb0e5ecc5cbbba028d5940499f2"}, + {file = "marisa_trie-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de62a115afd157fe6cfc8e4194905605c4603c6664eac30788f3f6866b67345f"}, + {file = "marisa_trie-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d7e17abb08ada031c86835e358242b6a2dc6645e1a872e30e1ce1c1b1cd6317d"}, + {file = "marisa_trie-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac288cb48e09927d96d00f4b2ad7bbfad91ce2e20fc6e6bb8b61dda05dbc28d2"}, + {file = "marisa_trie-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da0d59b93a327d772b49d9a79ef11f2e1c23aaafcefeab95376447794318d189"}, + {file = "marisa_trie-1.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d810f95a548751484bd57cfe5940ea5423d4e39678a10c9582b3f102fac27bbe"}, + {file = "marisa_trie-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:521a954dd469a336e3c8a307f7fe7ba272032d77cc8f801edebf2d11549ac1c2"}, + {file = "marisa_trie-1.1.0-cp38-cp38-win32.whl", hash = "sha256:1b25422875673ca5a15e236f2158f6a277f7252057272bb0b51272f4a9d3c401"}, + {file = "marisa_trie-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:c80b85559e09ec7f69b9f623ea06fd5cfe25ead20bb4a09c20e879cd1851db35"}, + {file = "marisa_trie-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:844a56eebe32b098b6d97af28bfa9ca576400b5560be8a09c021a521faadee4a"}, + {file = "marisa_trie-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:917ef793e0e90bd01fc436cebf93707de1ac31f2feadc4d4b0ddbdb9522617d5"}, + {file = "marisa_trie-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e09cb17288a5a43431e23737d2d91bd54e6d694380740267960dbc7ab96ad69d"}, + {file = "marisa_trie-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5353d3c8c48524aac40c325794d6227c59e517a68746d3a0524608a20438a1e9"}, + {file = "marisa_trie-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d4dd18d1c67a949eeaba16385ab2c1a3e1eb7a2acb982c3744193a59df30cfd"}, + {file = "marisa_trie-1.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4a9a17507211700c77849d1caf4e6a64756536e491327cda3ea12259ce70eae5"}, + {file = "marisa_trie-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6699b0d3ca090172713bfbb9ef8063bfe27cae8d05121d5f71d1c4048b57936d"}, + {file = "marisa_trie-1.1.0-cp39-cp39-win32.whl", hash = "sha256:b4450a4917af45614edc3da1ab1b927b96de01e5742719c330e6d4a0e36fee7d"}, + {file = "marisa_trie-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:89ba0ba6a05683d1ea966afe7aeae114d13fd8f354c6692a90bc2b181657ccbf"}, + {file = "marisa_trie-1.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:10665a17a7965c2a49b2dda6beb14cf206f6932f013ca0337105a8744d67395d"}, + {file = "marisa_trie-1.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86365aac6dde7228b0090d0e993f3ed557a43111cbe3b397f1bad77febbab342"}, + {file = "marisa_trie-1.1.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:086d7c2b45b03185c70431450e7b92e76d3f3333074bf9b3aabb2eb6e1b85f89"}, + {file = "marisa_trie-1.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9e5450eb023bf7a232cdaaf18fbe67fe45ed724d5cb30dd35f48c3a723ad3a4f"}, + {file = "marisa_trie-1.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:206db942691d82310cdb6c59e34acbe648766ddb569c13de8b534e17892c608c"}, + {file = "marisa_trie-1.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e12de8aea7fde90b4128bb8340a99cfb4a55e4c41b6336d187660e899385"}, + {file = "marisa_trie-1.1.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8652141e4623b36017275a6ae6efe7a2ece3b304b984d4f66acb620a78eed9"}, + {file = "marisa_trie-1.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:7916ddd3cf621a20285256e4e5e5e7e6c86aa29356faa31cc8de535b8b71afe3"}, + {file = "marisa_trie-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c57f2d6caa71829973a18b80c70b422337328686d3c7ea4519082f0b291fa01"}, + {file = "marisa_trie-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd45429b25098034a9ca2fc78877e3edc9d59f88ca8b3c69cff5f299c728d771"}, + {file = "marisa_trie-1.1.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71ee2edb2574b87a2173d64dd3f79c8e1af2e8d7bd1469bdcfe5fd895ada913a"}, + {file = "marisa_trie-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:427ce824566382309a300a8d080a84ccf6795325204c834839bdcb41203591f4"}, + {file = "marisa_trie-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37fcb2265d73a5c04829b25af7cdf819a27d71a898a6e1b54822e006f1843c94"}, + {file = "marisa_trie-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b34ea73a92c35577171bf9d8216e6c57acdf08b77b5d84f1efad8cf721159da"}, + {file = "marisa_trie-1.1.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdd7445f2f2785c02c18d46acf0c14baffafa6e7e73b3e9052b512e1f7dadbb3"}, + {file = "marisa_trie-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e0f4c47fca455bd75cab9e2181138d3978721ed546e2ed18e83b0852c49eca4f"}, ] [package.dependencies] @@ -1334,90 +1005,6 @@ files = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] -[[package]] -name = "more-itertools" -version = "10.5.0" -description = "More routines for operating on iterables, beyond itertools" -optional = false -python-versions = ">=3.8" -files = [ - {file = "more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6"}, - {file = "more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef"}, -] - -[[package]] -name = "msgpack" -version = "1.1.0" -description = "MessagePack serializer" -optional = false -python-versions = ">=3.8" -files = [ - {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, - {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, - {file = "msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b"}, - {file = "msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044"}, - {file = "msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"}, - {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"}, - {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"}, - {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"}, - {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"}, - {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"}, - {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f"}, - {file = "msgpack-1.1.0-cp38-cp38-win32.whl", hash = "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b"}, - {file = "msgpack-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8"}, - {file = "msgpack-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd"}, - {file = "msgpack-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325"}, - {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, -] - [[package]] name = "mutagen" version = "1.47.0" @@ -1429,143 +1016,26 @@ files = [ {file = "mutagen-1.47.0.tar.gz", hash = "sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99"}, ] -[[package]] -name = "packaging" -version = "24.2" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, -] - [[package]] name = "pefile" -version = "2024.8.26" +version = "2023.2.7" description = "Python PE parsing module" optional = false python-versions = ">=3.6.0" files = [ - {file = "pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f"}, - {file = "pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632"}, + {file = "pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6"}, + {file = "pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc"}, ] -[[package]] -name = "pexpect" -version = "4.9.0" -description = "Pexpect allows easy control of interactive console applications." -optional = false -python-versions = "*" -files = [ - {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, - {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, -] - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "pkginfo" -version = "1.12.0" -description = "Query metadata from sdists / bdists / installed packages." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pkginfo-1.12.0-py3-none-any.whl", hash = "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088"}, - {file = "pkginfo-1.12.0.tar.gz", hash = "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf"}, -] - -[package.extras] -testing = ["pytest", "pytest-cov", "wheel"] - -[[package]] -name = "platformdirs" -version = "4.3.6" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] - -[[package]] -name = "poetry" -version = "1.8.5" -description = "Python dependency management and packaging made easy." -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "poetry-1.8.5-py3-none-any.whl", hash = "sha256:5505fba69bf2a792b5d7402d21839c853644337392b745109b86a23010cce5f3"}, - {file = "poetry-1.8.5.tar.gz", hash = "sha256:eb2c88d224f58f36df8f7b36d6c380c07d1001bca28bde620f68fc086e881b70"}, -] - -[package.dependencies] -build = ">=1.0.3,<2.0.0" -cachecontrol = {version = ">=0.14.0,<0.15.0", extras = ["filecache"]} -cleo = ">=2.1.0,<3.0.0" -crashtest = ">=0.4.1,<0.5.0" -dulwich = ">=0.21.2,<0.22.0" -fastjsonschema = ">=2.18.0,<3.0.0" -importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} -installer = ">=0.7.0,<0.8.0" -keyring = ">=24.0.0,<25.0.0" -packaging = ">=23.1" -pexpect = ">=4.7.0,<5.0.0" -pkginfo = ">=1.12,<2.0" -platformdirs = ">=3.0.0,<5" -poetry-core = "1.9.1" -poetry-plugin-export = ">=1.6.0,<2.0.0" -pyproject-hooks = ">=1.0.0,<2.0.0" -requests = ">=2.26,<3.0" -requests-toolbelt = ">=1.0.0,<2.0.0" -shellingham = ">=1.5,<2.0" -tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} -tomlkit = ">=0.11.4,<1.0.0" -trove-classifiers = ">=2022.5.19" -virtualenv = ">=20.26.6,<21.0.0" -xattr = {version = ">=1.0.0,<2.0.0", markers = "sys_platform == \"darwin\""} - -[[package]] -name = "poetry-core" -version = "1.9.1" -description = "Poetry PEP 517 Build Backend" -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "poetry_core-1.9.1-py3-none-any.whl", hash = "sha256:6f45dd3598e0de8d9b0367360253d4c5d4d0110c8f5c71120a14f0e0f116c1a0"}, - {file = "poetry_core-1.9.1.tar.gz", hash = "sha256:7a2d49214bf58b4f17f99d6891d947a9836c9899a67a5069f52d7b67217f61b8"}, -] - -[[package]] -name = "poetry-plugin-export" -version = "1.8.0" -description = "Poetry plugin to export the dependencies to various formats" -optional = false -python-versions = "<4.0,>=3.8" -files = [ - {file = "poetry_plugin_export-1.8.0-py3-none-any.whl", hash = "sha256:adbe232cfa0cc04991ea3680c865cf748bff27593b9abcb1f35fb50ed7ba2c22"}, - {file = "poetry_plugin_export-1.8.0.tar.gz", hash = "sha256:1fa6168a85d59395d835ca564bc19862a7c76061e60c3e7dfaec70d50937fc61"}, -] - -[package.dependencies] -poetry = ">=1.8.0,<3.0.0" -poetry-core = ">=1.7.0,<3.0.0" - [[package]] name = "pproxy" -version = "2.7.9" +version = "2.7.8" description = "Proxy server that can tunnel among remote servers by regex rules." optional = false python-versions = ">=3.6" files = [ - {file = "pproxy-2.7.9-py3-none-any.whl", hash = "sha256:a073d02616a47c43e1d20a547918c307dbda598c6d53869b165025f3cfe58e80"}, + {file = "pproxy-2.7.8-py3-none-any.whl", hash = "sha256:9f300bae5288c7c7f56be70d6275571efd2b4862f306d25bdace3c3537fb53a7"}, + {file = "pproxy-2.7.8.tar.gz", hash = "sha256:fab73cc13b2bb10c9fc4d9c1a8ec8011a354c9bcbffa446d91229e13c5d996c8"}, ] [package.extras] @@ -1576,49 +1046,33 @@ sshtunnel = ["asyncssh (>=2.5.0)"] [[package]] name = "protobuf" -version = "4.25.5" -description = "" +version = "3.20.3" +description = "Protocol Buffers" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "protobuf-4.25.5-cp310-abi3-win32.whl", hash = "sha256:5e61fd921603f58d2f5acb2806a929b4675f8874ff5f330b7d6f7e2e784bbcd8"}, - {file = "protobuf-4.25.5-cp310-abi3-win_amd64.whl", hash = "sha256:4be0571adcbe712b282a330c6e89eae24281344429ae95c6d85e79e84780f5ea"}, - {file = "protobuf-4.25.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2fde3d805354df675ea4c7c6338c1aecd254dfc9925e88c6d31a2bcb97eb173"}, - {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:919ad92d9b0310070f8356c24b855c98df2b8bd207ebc1c0c6fcc9ab1e007f3d"}, - {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fe14e16c22be926d3abfcb500e60cab068baf10b542b8c858fa27e098123e331"}, - {file = "protobuf-4.25.5-cp38-cp38-win32.whl", hash = "sha256:98d8d8aa50de6a2747efd9cceba361c9034050ecce3e09136f90de37ddba66e1"}, - {file = "protobuf-4.25.5-cp38-cp38-win_amd64.whl", hash = "sha256:b0234dd5a03049e4ddd94b93400b67803c823cfc405689688f59b34e0742381a"}, - {file = "protobuf-4.25.5-cp39-cp39-win32.whl", hash = "sha256:abe32aad8561aa7cc94fc7ba4fdef646e576983edb94a73381b03c53728a626f"}, - {file = "protobuf-4.25.5-cp39-cp39-win_amd64.whl", hash = "sha256:7a183f592dc80aa7c8da7ad9e55091c4ffc9497b3054452d629bb85fa27c2a45"}, - {file = "protobuf-4.25.5-py3-none-any.whl", hash = "sha256:0aebecb809cae990f8129ada5ca273d9d670b76d9bfc9b1809f0a9c02b7dbf41"}, - {file = "protobuf-4.25.5.tar.gz", hash = "sha256:7f8249476b4a9473645db7f8ab42b02fe1488cbe5fb72fddd445e0665afd8584"}, -] - -[[package]] -name = "protobuf3" -version = "3.20.2" -description = "protobuf3" -optional = false -python-versions = ">=3.7,<4.0" -files = [] -develop = true - -[package.dependencies] -requests = "^2.32.3" - -[package.source] -type = "directory" -url = "scripts/protobuf3" - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -optional = false -python-versions = "*" -files = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, + {file = "protobuf-3.20.3-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99"}, + {file = "protobuf-3.20.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e"}, + {file = "protobuf-3.20.3-cp310-cp310-win32.whl", hash = "sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c"}, + {file = "protobuf-3.20.3-cp310-cp310-win_amd64.whl", hash = "sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7"}, + {file = "protobuf-3.20.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469"}, + {file = "protobuf-3.20.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4"}, + {file = "protobuf-3.20.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4"}, + {file = "protobuf-3.20.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454"}, + {file = "protobuf-3.20.3-cp37-cp37m-win32.whl", hash = "sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905"}, + {file = "protobuf-3.20.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c"}, + {file = "protobuf-3.20.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7"}, + {file = "protobuf-3.20.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee"}, + {file = "protobuf-3.20.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050"}, + {file = "protobuf-3.20.3-cp38-cp38-win32.whl", hash = "sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86"}, + {file = "protobuf-3.20.3-cp38-cp38-win_amd64.whl", hash = "sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9"}, + {file = "protobuf-3.20.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b"}, + {file = "protobuf-3.20.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b"}, + {file = "protobuf-3.20.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402"}, + {file = "protobuf-3.20.3-cp39-cp39-win32.whl", hash = "sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480"}, + {file = "protobuf-3.20.3-cp39-cp39-win_amd64.whl", hash = "sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7"}, + {file = "protobuf-3.20.3-py2.py3-none-any.whl", hash = "sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db"}, + {file = "protobuf-3.20.3.tar.gz", hash = "sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2"}, ] [[package]] @@ -1654,13 +1108,13 @@ files = [ [[package]] name = "pycparser" -version = "2.22" +version = "2.21" description = "C parser in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] [[package]] @@ -1706,43 +1160,43 @@ files = [ [[package]] name = "pycryptodomex" -version = "3.21.0" +version = "3.19.0" description = "Cryptographic library for Python" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycryptodomex-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dbeb84a399373df84a69e0919c1d733b89e049752426041deeb30d68e9867822"}, - {file = "pycryptodomex-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a192fb46c95489beba9c3f002ed7d93979423d1b2a53eab8771dbb1339eb3ddd"}, - {file = "pycryptodomex-3.21.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:1233443f19d278c72c4daae749872a4af3787a813e05c3561c73ab0c153c7b0f"}, - {file = "pycryptodomex-3.21.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbb07f88e277162b8bfca7134b34f18b400d84eac7375ce73117f865e3c80d4c"}, - {file = "pycryptodomex-3.21.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e859e53d983b7fe18cb8f1b0e29d991a5c93be2c8dd25db7db1fe3bd3617f6f9"}, - {file = "pycryptodomex-3.21.0-cp27-cp27m-win32.whl", hash = "sha256:ef046b2e6c425647971b51424f0f88d8a2e0a2a63d3531817968c42078895c00"}, - {file = "pycryptodomex-3.21.0-cp27-cp27m-win_amd64.whl", hash = "sha256:da76ebf6650323eae7236b54b1b1f0e57c16483be6e3c1ebf901d4ada47563b6"}, - {file = "pycryptodomex-3.21.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:c07e64867a54f7e93186a55bec08a18b7302e7bee1b02fd84c6089ec215e723a"}, - {file = "pycryptodomex-3.21.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:56435c7124dd0ce0c8bdd99c52e5d183a0ca7fdcd06c5d5509423843f487dd0b"}, - {file = "pycryptodomex-3.21.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65d275e3f866cf6fe891411be9c1454fb58809ccc5de6d3770654c47197acd65"}, - {file = "pycryptodomex-3.21.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:5241bdb53bcf32a9568770a6584774b1b8109342bd033398e4ff2da052123832"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:34325b84c8b380675fd2320d0649cdcbc9cf1e0d1526edbe8fce43ed858cdc7e"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:103c133d6cd832ae7266feb0a65b69e3a5e4dbbd6f3a3ae3211a557fd653f516"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77ac2ea80bcb4b4e1c6a596734c775a1615d23e31794967416afc14852a639d3"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9aa0cf13a1a1128b3e964dc667e5fe5c6235f7d7cfb0277213f0e2a783837cc2"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46eb1f0c8d309da63a2064c28de54e5e614ad17b7e2f88df0faef58ce192fc7b"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:cc7e111e66c274b0df5f4efa679eb31e23c7545d702333dfd2df10ab02c2a2ce"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:770d630a5c46605ec83393feaa73a9635a60e55b112e1fb0c3cea84c2897aa0a"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:52e23a0a6e61691134aa8c8beba89de420602541afaae70f66e16060fdcd677e"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-win32.whl", hash = "sha256:a3d77919e6ff56d89aada1bd009b727b874d464cb0e2e3f00a49f7d2e709d76e"}, - {file = "pycryptodomex-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b0e9765f93fe4890f39875e6c90c96cb341767833cfa767f41b490b506fa9ec0"}, - {file = "pycryptodomex-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:feaecdce4e5c0045e7a287de0c4351284391fe170729aa9182f6bd967631b3a8"}, - {file = "pycryptodomex-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:365aa5a66d52fd1f9e0530ea97f392c48c409c2f01ff8b9a39c73ed6f527d36c"}, - {file = "pycryptodomex-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3efddfc50ac0ca143364042324046800c126a1d63816d532f2e19e6f2d8c0c31"}, - {file = "pycryptodomex-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df2608682db8279a9ebbaf05a72f62a321433522ed0e499bc486a6889b96bf3"}, - {file = "pycryptodomex-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5823d03e904ea3e53aebd6799d6b8ec63b7675b5d2f4a4bd5e3adcb512d03b37"}, - {file = "pycryptodomex-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:27e84eeff24250ffec32722334749ac2a57a5fd60332cd6a0680090e7c42877e"}, - {file = "pycryptodomex-3.21.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8ef436cdeea794015263853311f84c1ff0341b98fc7908e8a70595a68cefd971"}, - {file = "pycryptodomex-3.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1058e6dfe827f4209c5cae466e67610bcd0d66f2f037465daa2a29d92d952b"}, - {file = "pycryptodomex-3.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ba09a5b407cbb3bcb325221e346a140605714b5e880741dc9a1e9ecf1688d42"}, - {file = "pycryptodomex-3.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8a9d8342cf22b74a746e3c6c9453cb0cfbb55943410e3a2619bd9164b48dc9d9"}, - {file = "pycryptodomex-3.21.0.tar.gz", hash = "sha256:222d0bd05381dd25c32dd6065c071ebf084212ab79bab4599ba9e6a3e0009e6c"}, + {file = "pycryptodomex-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff64fd720def623bf64d8776f8d0deada1cc1bf1ec3c1f9d6f5bb5bd098d034f"}, + {file = "pycryptodomex-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:61056a1fd3254f6f863de94c233b30dd33bc02f8c935b2000269705f1eeeffa4"}, + {file = "pycryptodomex-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:258c4233a3fe5a6341780306a36c6fb072ef38ce676a6d41eec3e591347919e8"}, + {file = "pycryptodomex-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e45bb4635b3c4e0a00ca9df75ef6295838c85c2ac44ad882410cb631ed1eeaa"}, + {file = "pycryptodomex-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a12144d785518f6491ad334c75ccdc6ad52ea49230b4237f319dbb7cef26f464"}, + {file = "pycryptodomex-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:1789d89f61f70a4cd5483d4dfa8df7032efab1118f8b9894faae03c967707865"}, + {file = "pycryptodomex-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:eb2fc0ec241bf5e5ef56c8fbec4a2634d631e4c4f616a59b567947a0f35ad83c"}, + {file = "pycryptodomex-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:c9a68a2f7bd091ccea54ad3be3e9d65eded813e6d79fdf4cc3604e26cdd6384f"}, + {file = "pycryptodomex-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:8df69e41f7e7015a90b94d1096ec3d8e0182e73449487306709ec27379fff761"}, + {file = "pycryptodomex-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:917033016ecc23c8933205585a0ab73e20020fdf671b7cd1be788a5c4039840b"}, + {file = "pycryptodomex-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:e8e5ecbd4da4157889fce8ba49da74764dd86c891410bfd6b24969fa46edda51"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:a77b79852175064c822b047fee7cf5a1f434f06ad075cc9986aa1c19a0c53eb0"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5b883e1439ab63af976656446fb4839d566bb096f15fc3c06b5a99cde4927188"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3866d68e2fc345162b1b9b83ef80686acfe5cec0d134337f3b03950a0a8bf56"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74eb1f73f788facece7979ce91594dc177e1a9b5d5e3e64697dd58299e5cb4d"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cb51096a6a8d400724104db8a7e4f2206041a1f23e58924aa3d8d96bcb48338"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a588a1cb7781da9d5e1c84affd98c32aff9c89771eac8eaa659d2760666f7139"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:d4dd3b381ff5a5907a3eb98f5f6d32c64d319a840278ceea1dcfcc65063856f3"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:263de9a96d2fcbc9f5bd3a279f14ea0d5f072adb68ebd324987576ec25da084d"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-win32.whl", hash = "sha256:67c8eb79ab33d0fbcb56842992298ddb56eb6505a72369c20f60bc1d2b6fb002"}, + {file = "pycryptodomex-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:09c9401dc06fb3d94cb1ec23b4ea067a25d1f4c6b7b118ff5631d0b5daaab3cc"}, + {file = "pycryptodomex-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:edbe083c299835de7e02c8aa0885cb904a75087d35e7bab75ebe5ed336e8c3e2"}, + {file = "pycryptodomex-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:136b284e9246b4ccf4f752d435c80f2c44fc2321c198505de1d43a95a3453b3c"}, + {file = "pycryptodomex-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5d73e9fa3fe830e7b6b42afc49d8329b07a049a47d12e0ef9225f2fd220f19b2"}, + {file = "pycryptodomex-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b2f1982c5bc311f0aab8c293524b861b485d76f7c9ab2c3ac9a25b6f7655975"}, + {file = "pycryptodomex-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb040b5dda1dff1e197d2ef71927bd6b8bfcb9793bc4dfe0bb6df1e691eaacb"}, + {file = "pycryptodomex-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:800a2b05cfb83654df80266692f7092eeefe2a314fa7901dcefab255934faeec"}, + {file = "pycryptodomex-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c01678aee8ac0c1a461cbc38ad496f953f9efcb1fa19f5637cbeba7544792a53"}, + {file = "pycryptodomex-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2126bc54beccbede6eade00e647106b4f4c21e5201d2b0a73e9e816a01c50905"}, + {file = "pycryptodomex-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b801216c48c0886742abf286a9a6b117e248ca144d8ceec1f931ce2dd0c9cb40"}, + {file = "pycryptodomex-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:50cb18d4dd87571006fd2447ccec85e6cec0136632a550aa29226ba075c80644"}, + {file = "pycryptodomex-3.19.0.tar.gz", hash = "sha256:af83a554b3f077564229865c45af0791be008ac6469ef0098152139e6bd4b5b6"}, ] [[package]] @@ -1800,20 +1254,15 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2025.0" +version = "2023.10" description = "Community maintained hooks for PyInstaller" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pyinstaller_hooks_contrib-2025.0-py3-none-any.whl", hash = "sha256:3c0623799c3f81a37293127f485d65894c20fd718f722cb588785a3e52581ad1"}, - {file = "pyinstaller_hooks_contrib-2025.0.tar.gz", hash = "sha256:6dc0b55a1acaab2ffee36ed4a05b073aa0a22e46f25fb5c66a31e217454135ed"}, + {file = "pyinstaller-hooks-contrib-2023.10.tar.gz", hash = "sha256:4b4a998036abb713774cb26534ca06b7e6e09e4c628196017a10deb11a48747f"}, + {file = "pyinstaller_hooks_contrib-2023.10-py2.py3-none-any.whl", hash = "sha256:6dc1786a8f452941245d5bb85893e2a33632ebdcbc4c23eea41f2ee08281b0c0"}, ] -[package.dependencies] -importlib_metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} -packaging = ">=22.0" -setuptools = ">=42.0.0" - [[package]] name = "pymediainfo" version = "5.1.0" @@ -1827,29 +1276,15 @@ files = [ {file = "pymediainfo-5.1.0.tar.gz", hash = "sha256:d996c69d50081a24d6dca9679abf43ffd2be368b065f953c2c9082e5d649c734"}, ] -[[package]] -name = "pymp4" -version = "1.4.0" -description = "Python parser for MP4 boxes" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "pymp4-1.4.0-py3-none-any.whl", hash = "sha256:3401666c1e2a97ac94dffb18c5a5dcbd46d0a436da5272d378a6f9f6506dd12d"}, - {file = "pymp4-1.4.0.tar.gz", hash = "sha256:bc9e77732a8a143d34c38aa862a54180716246938e4bf3e07585d19252b77bb5"}, -] - -[package.dependencies] -construct = "2.8.8" - [[package]] name = "pymysql" -version = "1.1.1" +version = "1.1.0" description = "Pure Python MySQL Driver" optional = false python-versions = ">=3.7" files = [ - {file = "PyMySQL-1.1.1-py3-none-any.whl", hash = "sha256:4de15da4c61dc132f4fb9ab763063e693d521a80fd0e87943b9a453dd4c19d6c"}, - {file = "pymysql-1.1.1.tar.gz", hash = "sha256:e127611aaf2b417403c60bf4dc570124aeb4a57f5f37b8e95ae399a42f904cd0"}, + {file = "PyMySQL-1.1.0-py3-none-any.whl", hash = "sha256:8969ec6d763c856f7073c4c64662882675702efcb114b4bcbb955aea3a069fa7"}, + {file = "PyMySQL-1.1.0.tar.gz", hash = "sha256:4f13a7df8bf36a51e81dd9f3605fede45a4878fe02f9236349fd82a3f0612f96"}, ] [package.dependencies] @@ -1859,53 +1294,17 @@ cryptography = {version = "*", optional = true, markers = "extra == \"rsa\""} ed25519 = ["PyNaCl (>=1.4.0)"] rsa = ["cryptography"] -[[package]] -name = "pyplayready" -version = "0.5.0" -description = "pyplayready CDM (Content Decryption Module) implementation in Python." -optional = false -python-versions = ">=3.8,<4.0" -files = [] -develop = true - -[package.dependencies] -click = "^8.1.7" -construct = "^2.8.8" -ECPy = "^1.2.5" -pycryptodome = "^3.21.0" -PyYAML = "^6.0.1" -requests = "^2.32.3" -xmltodict = "^0.14.2" - -[package.source] -type = "directory" -url = "scripts/pyplayready" - -[[package]] -name = "pyproject-hooks" -version = "1.2.0" -description = "Wrappers to call pyproject.toml-based build backend hooks." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"}, - {file = "pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8"}, -] - [[package]] name = "pyreadline3" -version = "3.5.4" +version = "3.4.1" description = "A python implementation of GNU readline." optional = false -python-versions = ">=3.8" +python-versions = "*" files = [ - {file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"}, - {file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"}, + {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"}, + {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, ] -[package.extras] -dev = ["build", "flake8", "mypy", "pytest", "twine"] - [[package]] name = "pysocks" version = "1.7.1" @@ -1920,241 +1319,95 @@ files = [ [[package]] name = "pysubs2" -version = "1.7.3" +version = "1.6.1" description = "A library for editing subtitle files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pysubs2-1.7.3-py3-none-any.whl", hash = "sha256:de438c868d2c656781c4a78f220ec3a6fd6d52be49266c81fe912d2527002d44"}, - {file = "pysubs2-1.7.3.tar.gz", hash = "sha256:b0130f373390736754531be4e68a0fa521e825fa15cc8ff506e4f8ca2c17459a"}, + {file = "pysubs2-1.6.1-py3-none-any.whl", hash = "sha256:1f96d9dfb5f859a54a00e04621beb20ff21ea1d788821b2f4935c5c0ef8dc68e"}, + {file = "pysubs2-1.6.1.tar.gz", hash = "sha256:0261611e71735ff7763972c519c72593c8063efcb9039c54af65f31b81cec116"}, ] -[[package]] -name = "pywidevine" -version = "1.8.0" -description = "Widevine CDM (Content Decryption Module) implementation in Python." -optional = false -python-versions = ">=3.8,<4.0" -files = [] -develop = true - -[package.dependencies] -click = "^8.1.7" -protobuf = "^4.25.1" -pycryptodome = "^3.19.0" -PyYAML = "^6.0.1" -requests = "^2.31.0" -Unidecode = "^1.3.7" - -[package.extras] -serve = ["aiohttp (>=3.9.1,<4.0.0)"] - -[package.source] -type = "directory" -url = "scripts/pywidevine" - [[package]] name = "pywin32-ctypes" -version = "0.2.3" +version = "0.2.2" description = "A (partial) reimplementation of pywin32 using ctypes/cffi" optional = false python-versions = ">=3.6" files = [ - {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, - {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, + {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, + {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, ] [[package]] name = "pyyaml" -version = "6.0.2" +version = "6.0.1" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] -[[package]] -name = "rapidfuzz" -version = "3.9.7" -description = "rapid fuzzy string matching" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rapidfuzz-3.9.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ccf68e30b80e903f2309f90a438dbd640dd98e878eeb5ad361a288051ee5b75c"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:696a79018ef989bf1c9abd9005841cee18005ccad4748bad8a4c274c47b6241a"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4eebf6c93af0ae866c22b403a84747580bb5c10f0d7b51c82a87f25405d4dcb"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e9125377fa3d21a8abd4fbdbcf1c27be73e8b1850f0b61b5b711364bf3b59db"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c12d180b17a22d107c8747de9c68d0b9c1d15dcda5445ff9bf9f4ccfb67c3e16"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1318d42610c26dcd68bd3279a1bf9e3605377260867c9a8ed22eafc1bd93a7c"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5fa6e3c6e0333051c1f3a49f0807b3366f4131c8d6ac8c3e05fd0d0ce3755c"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fcf79b686962d7bec458a0babc904cb4fa319808805e036b9d5a531ee6b9b835"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8b01153c7466d0bad48fba77a303d5a768e66f24b763853469f47220b3de4661"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:94baaeea0b4f8632a6da69348b1e741043eba18d4e3088d674d3f76586b6223d"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6c5b32875646cb7f60c193ade99b2e4b124f19583492115293cd00f6fb198b17"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:110b6294396bc0a447648627479c9320f095c2034c0537f687592e0f58622638"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-win32.whl", hash = "sha256:3445a35c4c8d288f2b2011eb61bce1227c633ce85a3154e727170f37c0266bb2"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-win_amd64.whl", hash = "sha256:0d1415a732ee75e74a90af12020b77a0b396b36c60afae1bde3208a78cd2c9fc"}, - {file = "rapidfuzz-3.9.7-cp310-cp310-win_arm64.whl", hash = "sha256:836f4d88b8bd0fff2ebe815dcaab8aa6c8d07d1d566a7e21dd137cf6fe11ed5b"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d098ce6162eb5e48fceb0745455bc950af059df6113eec83e916c129fca11408"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:048d55d36c02c6685a2b2741688503c3d15149694506655b6169dcfd3b6c2585"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c33211cfff9aec425bb1bfedaf94afcf337063aa273754f22779d6dadebef4c2"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6d9db2fa4e9be171e9bb31cf2d2575574774966b43f5b951062bb2e67885852"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4e049d5ad61448c9a020d1061eba20944c4887d720c4069724beb6ea1692507"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cfa74aac64c85898b93d9c80bb935a96bf64985e28d4ee0f1a3d1f3bf11a5106"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:965693c2e9efd425b0f059f5be50ef830129f82892fa1858e220e424d9d0160f"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8501000a5eb8037c4b56857724797fe5a8b01853c363de91c8d0d0ad56bef319"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d92c552c6b7577402afdd547dcf5d31ea6c8ae31ad03f78226e055cfa37f3c6"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1ee2086f490cb501d86b7e386c1eb4e3a0ccbb0c99067089efaa8c79012c8952"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1de91e7fd7f525e10ea79a6e62c559d1b0278ec097ad83d9da378b6fab65a265"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a4da514d13f4433e16960a17f05b67e0af30ac771719c9a9fb877e5004f74477"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-win32.whl", hash = "sha256:a40184c67db8252593ec518e17fb8a6e86d7259dc9f2d6c0bf4ff4db8cf1ad4b"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-win_amd64.whl", hash = "sha256:c4f28f1930b09a2c300357d8465b388cecb7e8b2f454a5d5425561710b7fd07f"}, - {file = "rapidfuzz-3.9.7-cp311-cp311-win_arm64.whl", hash = "sha256:675b75412a943bb83f1f53e2e54fd18c80ef15ed642dc6eb0382d1949419d904"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1ef6a1a8f0b12f8722f595f15c62950c9a02d5abc64742561299ffd49f6c6944"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:32532af1d70c6ec02ea5ac7ee2766dfff7c8ae8c761abfe8da9e527314e634e8"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1a38bade755aa9dd95a81cda949e1bf9cd92b79341ccc5e2189c9e7bdfc5ec"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d73ee2df41224c87336448d279b5b6a3a75f36e41dd3dcf538c0c9cce36360d8"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be3a1fc3e2ab3bdf93dc0c83c00acca8afd2a80602297d96cf4a0ba028333cdf"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:603f48f621272a448ff58bb556feb4371252a02156593303391f5c3281dfaeac"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:268f8e1ca50fc61c0736f3fe9d47891424adf62d96ed30196f30f4bd8216b41f"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f8bf3f0d02935751d8660abda6044821a861f6229f7d359f98bcdcc7e66c39b"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b997ff3b39d4cee9fb025d6c46b0a24bd67595ce5a5b652a97fb3a9d60beb651"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ca66676c8ef6557f9b81c5b2b519097817a7c776a6599b8d6fcc3e16edd216fe"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:35d3044cb635ca6b1b2b7b67b3597bd19f34f1753b129eb6d2ae04cf98cd3945"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5a93c9e60904cb76e7aefef67afffb8b37c4894f81415ed513db090f29d01101"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-win32.whl", hash = "sha256:579d107102c0725f7c79b4e79f16d3cf4d7c9208f29c66b064fa1fd4641d5155"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-win_amd64.whl", hash = "sha256:953b3780765c8846866faf891ee4290f6a41a6dacf4fbcd3926f78c9de412ca6"}, - {file = "rapidfuzz-3.9.7-cp312-cp312-win_arm64.whl", hash = "sha256:7c20c1474b068c4bd45bf2fd0ad548df284f74e9a14a68b06746c56e3aa8eb70"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fde81b1da9a947f931711febe2e2bee694e891f6d3e6aa6bc02c1884702aea19"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:47e92c155a14f44511ea8ebcc6bc1535a1fe8d0a7d67ad3cc47ba61606df7bcf"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8772b745668260c5c4d069c678bbaa68812e6c69830f3771eaad521af7bc17f8"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:578302828dd97ee2ba507d2f71d62164e28d2fc7bc73aad0d2d1d2afc021a5d5"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc3e6081069eea61593f1d6839029da53d00c8c9b205c5534853eaa3f031085c"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0b1c2d504eddf97bc0f2eba422c8915576dbf025062ceaca2d68aecd66324ad9"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb76e5a21034f0307c51c5a2fc08856f698c53a4c593b17d291f7d6e9d09ca3"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d4ba2318ef670ce505f42881a5d2af70f948124646947341a3c6ccb33cd70369"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:057bb03f39e285047d7e9412e01ecf31bb2d42b9466a5409d715d587460dd59b"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a8feac9006d5c9758438906f093befffc4290de75663dbb2098461df7c7d28dd"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:95b8292383e717e10455f2c917df45032b611141e43d1adf70f71b1566136b11"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e9fbf659537d246086d0297628b3795dc3e4a384101ecc01e5791c827b8d7345"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-win32.whl", hash = "sha256:1dc516ac6d32027be2b0196bedf6d977ac26debd09ca182376322ad620460feb"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-win_amd64.whl", hash = "sha256:b4f86e09d3064dca0b014cd48688964036a904a2d28048f00c8f4640796d06a8"}, - {file = "rapidfuzz-3.9.7-cp313-cp313-win_arm64.whl", hash = "sha256:19c64d8ddb2940b42a4567b23f1681af77f50a5ff6c9b8e85daba079c210716e"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbda3dd68d8b28ccb20ffb6f756fefd9b5ba570a772bedd7643ed441f5793308"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2379e0b2578ad3ac7004f223251550f08bca873ff76c169b09410ec562ad78d8"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d1eff95362f993b0276fd3839aee48625b09aac8938bb0c23b40d219cba5dc5"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd9360e30041690912525a210e48a897b49b230768cc8af1c702e5395690464f"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a93cd834b3c315ab437f0565ee3a2f42dd33768dc885ccbabf9710b131cf70d2"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff196996240db7075f62c7bc4506f40a3c80cd4ae3ab0e79ac6892283a90859"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:948dcee7aaa1cd14358b2a7ef08bf0be42bf89049c3a906669874a715fc2c937"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95751f505a301af1aaf086c19f34536056d6c8efa91b2240de532a3db57b543"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:90db86fa196eecf96cb6db09f1083912ea945c50c57188039392d810d0b784e1"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:3171653212218a162540a3c8eb8ae7d3dcc8548540b69eaecaf3b47c14d89c90"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:36dd6e820379c37a1ffefc8a52b648758e867cd9d78ee5b5dc0c9a6a10145378"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7b702de95666a1f7d5c6b47eacadfe2d2794af3742d63d2134767d13e5d1c713"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-win32.whl", hash = "sha256:9030e7238c0df51aed5c9c5ed8eee2bdd47a2ae788e562c1454af2851c3d1906"}, - {file = "rapidfuzz-3.9.7-cp38-cp38-win_amd64.whl", hash = "sha256:f847fb0fbfb72482b1c05c59cbb275c58a55b73708a7f77a83f8035ee3c86497"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:97f2ce529d2a70a60c290f6ab269a2bbf1d3b47b9724dccc84339b85f7afb044"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e2957fdad10bb83b1982b02deb3604a3f6911a5e545f518b59c741086f92d152"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d5262383634626eb45c536017204b8163a03bc43bda880cf1bdd7885db9a163"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:364587827d7cbd41afa0782adc2d2d19e3f07d355b0750a02a8e33ad27a9c368"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecc24af7f905f3d6efb371a01680116ffea8d64e266618fb9ad1602a9b4f7934"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dc86aa6b29d174713c5f4caac35ffb7f232e3e649113e8d13812b35ab078228"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3dcfbe7266e74a707173a12a7b355a531f2dcfbdb32f09468e664330da14874"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b23806fbdd6b510ba9ac93bb72d503066263b0fba44b71b835be9f063a84025f"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5551d68264c1bb6943f542da83a4dc8940ede52c5847ef158698799cc28d14f5"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:13d8675a1fa7e2b19650ca7ef9a6ec01391d4bb12ab9e0793e8eb024538b4a34"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9b6a5de507b9be6de688dae40143b656f7a93b10995fb8bd90deb555e7875c60"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:111a20a3c090cf244d9406e60500b6c34b2375ba3a5009e2b38fd806fe38e337"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-win32.whl", hash = "sha256:22589c0b8ccc6c391ce7f776c93a8c92c96ab8d34e1a19f1bd2b12a235332632"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-win_amd64.whl", hash = "sha256:6f83221db5755b8f34222e40607d87f1176a8d5d4dbda4a55a0f0b67d588a69c"}, - {file = "rapidfuzz-3.9.7-cp39-cp39-win_arm64.whl", hash = "sha256:3665b92e788578c3bb334bd5b5fa7ee1a84bafd68be438e3110861d1578c63a0"}, - {file = "rapidfuzz-3.9.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7df9c2194c7ec930b33c991c55dbd0c10951bd25800c0b7a7b571994ebbced5"}, - {file = "rapidfuzz-3.9.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:68bd888eafd07b09585dcc8bc2716c5ecdb7eed62827470664d25588982b2873"}, - {file = "rapidfuzz-3.9.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1230e0f9026851a6a432beaa0ce575dda7b39fe689b576f99a0704fbb81fc9c"}, - {file = "rapidfuzz-3.9.7-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b36e1c61b796ae1777f3e9e11fd39898b09d351c9384baf6e3b7e6191d8ced"}, - {file = "rapidfuzz-3.9.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dba13d86806fcf3fe9c9919f58575e0090eadfb89c058bde02bcc7ab24e4548"}, - {file = "rapidfuzz-3.9.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1f1a33e84056b7892c721d84475d3bde49a145126bc4c6efe0d6d0d59cb31c29"}, - {file = "rapidfuzz-3.9.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3492c7a42b7fa9f0051d7fcce9893e95ed91c97c9ec7fb64346f3e070dd318ed"}, - {file = "rapidfuzz-3.9.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:ece45eb2af8b00f90d10f7419322e8804bd42fb1129026f9bfe712c37508b514"}, - {file = "rapidfuzz-3.9.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcd14cf4876f04b488f6e54a7abd3e9b31db5f5a6aba0ce90659917aaa8c088"}, - {file = "rapidfuzz-3.9.7-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:521c58c72ed8a612b25cda378ff10dee17e6deb4ee99a070b723519a345527b9"}, - {file = "rapidfuzz-3.9.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18669bb6cdf7d40738526d37e550df09ba065b5a7560f3d802287988b6cb63cf"}, - {file = "rapidfuzz-3.9.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7abe2dbae81120a64bb4f8d3fcafe9122f328c9f86d7f327f174187a5af4ed86"}, - {file = "rapidfuzz-3.9.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a3c0783910911f4f24655826d007c9f4360f08107410952c01ee3df98c713eb2"}, - {file = "rapidfuzz-3.9.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:03126f9a040ff21d2a110610bfd6b93b79377ce8b4121edcb791d61b7df6eec5"}, - {file = "rapidfuzz-3.9.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:591908240f4085e2ade5b685c6e8346e2ed44932cffeaac2fb32ddac95b55c7f"}, - {file = "rapidfuzz-3.9.7-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9012d86c6397edbc9da4ac0132de7f8ee9d6ce857f4194d5684c4ddbcdd1c5c"}, - {file = "rapidfuzz-3.9.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df596ddd3db38aa513d4c0995611267b3946e7cbe5a8761b50e9306dfec720ee"}, - {file = "rapidfuzz-3.9.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3ed5adb752f4308fcc8f4fb6f8eb7aa4082f9d12676fda0a74fa5564242a8107"}, - {file = "rapidfuzz-3.9.7.tar.gz", hash = "sha256:f1c7296534c1afb6f495aa95871f14ccdc197c6db42965854e483100df313030"}, -] - -[package.extras] -full = ["numpy"] - [[package]] name = "requests" -version = "2.32.3" +version = "2.29.0" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, + {file = "requests-2.29.0-py3-none-any.whl", hash = "sha256:e8f3c9be120d3333921d213eef078af392fba3933ab7ed2d1cba3b56f2568c3b"}, + {file = "requests-2.29.0.tar.gz", hash = "sha256:f2e34a75f4749019bb0e3effb66683630e4ffeaf75819fb51bebef1bf5aef059"}, ] [package.dependencies] @@ -2162,7 +1415,7 @@ certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" PySocks = {version = ">=1.5.6,<1.5.7 || >1.5.7", optional = true, markers = "extra == \"socks\""} -urllib3 = ">=1.21.1,<3" +urllib3 = ">=1.21.1,<1.27" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -2170,31 +1423,18 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-file" -version = "2.1.0" +version = "1.5.1" description = "File transport adapter for Requests" optional = false python-versions = "*" files = [ - {file = "requests_file-2.1.0-py2.py3-none-any.whl", hash = "sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c"}, - {file = "requests_file-2.1.0.tar.gz", hash = "sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658"}, + {file = "requests-file-1.5.1.tar.gz", hash = "sha256:07d74208d3389d01c38ab89ef403af0cfec63957d53a0081d8eca738d0247d8e"}, + {file = "requests_file-1.5.1-py2.py3-none-any.whl", hash = "sha256:dfe5dae75c12481f68ba353183c53a65e6044c923e64c24b2209f6c7570ca953"}, ] [package.dependencies] requests = ">=1.0.0" - -[[package]] -name = "requests-toolbelt" -version = "1.0.0" -description = "A utility belt for advanced users of python-requests" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, - {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, -] - -[package.dependencies] -requests = ">=2.0.1,<3.0.0" +six = "*" [[package]] name = "rfc3986" @@ -2213,83 +1453,53 @@ idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} [package.extras] idna2008 = ["idna"] -[[package]] -name = "secretstorage" -version = "3.3.3" -description = "Python bindings to FreeDesktop.org Secret Service API" -optional = false -python-versions = ">=3.6" -files = [ - {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, - {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, -] - -[package.dependencies] -cryptography = ">=2.0" -jeepney = ">=0.6" - [[package]] name = "setuptools" -version = "75.3.0" +version = "68.2.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"}, - {file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"}, + {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, + {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"] - -[[package]] -name = "shellingham" -version = "1.5.4" -description = "Tool to Detect Surrounding Shell" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, - {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, -] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" -version = "1.17.0" +version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ - {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, - {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] [[package]] name = "sniffio" -version = "1.3.1" +version = "1.3.0" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] [[package]] name = "soupsieve" -version = "2.6" +version = "2.5" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" files = [ - {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, - {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, ] [[package]] @@ -2320,128 +1530,32 @@ files = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] -[[package]] -name = "tomli" -version = "2.2.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.8" -files = [ - {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, - {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, - {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, - {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, - {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, - {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, - {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, - {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, - {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, - {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, -] - -[[package]] -name = "tomlkit" -version = "0.13.2" -description = "Style preserving TOML library" -optional = false -python-versions = ">=3.8" -files = [ - {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, - {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, -] - -[[package]] -name = "tqdm" -version = "4.67.1" -description = "Fast, Extensible Progress Meter" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, - {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] -discord = ["requests"] -notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] - -[[package]] -name = "trove-classifiers" -version = "2025.1.15.22" -description = "Canonical source for classifiers on PyPI (pypi.org)." -optional = false -python-versions = "*" -files = [ - {file = "trove_classifiers-2025.1.15.22-py3-none-any.whl", hash = "sha256:5f19c789d4f17f501d36c94dbbf969fb3e8c2784d008e6f5164dd2c3d6a2b07c"}, - {file = "trove_classifiers-2025.1.15.22.tar.gz", hash = "sha256:90af74358d3a01b3532bc7b3c88d8c6a094c2fd50a563d13d9576179326d7ed9"}, -] - -[[package]] -name = "typing-extensions" -version = "4.12.2" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, -] - [[package]] name = "unidecode" -version = "1.3.8" +version = "1.3.7" description = "ASCII transliterations of Unicode text" optional = false python-versions = ">=3.5" files = [ - {file = "Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39"}, - {file = "Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4"}, + {file = "Unidecode-1.3.7-py3-none-any.whl", hash = "sha256:663a537f506834ed836af26a81b210d90cbde044c47bfbdc0fbbc9f94c86a6e4"}, + {file = "Unidecode-1.3.7.tar.gz", hash = "sha256:3c90b4662aa0de0cb591884b934ead8d2225f1800d8da675a7750cbc3bd94610"}, ] [[package]] name = "urllib3" -version = "2.2.3" +version = "1.26.17" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, + {file = "urllib3-1.26.17-py2.py3-none-any.whl", hash = "sha256:94a757d178c9be92ef5539b8840d48dc9cf1b2709c9d6b588232a055c524458b"}, + {file = "urllib3-1.26.17.tar.gz", hash = "sha256:24d6a242c28d29af46c3fae832c36db3bbebcc533dd1bb549172cd739c82df21"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "validators" @@ -2461,231 +1575,110 @@ six = ">=1.4.0" [package.extras] test = ["flake8 (>=2.4.0)", "isort (>=4.2.2)", "pytest (>=2.2.3)"] -[[package]] -name = "virtualenv" -version = "20.29.1" -description = "Virtual Python Environment builder" -optional = false -python-versions = ">=3.8" -files = [ - {file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"}, - {file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"}, -] - -[package.dependencies] -distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<5" - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] - [[package]] name = "websocket-client" -version = "1.8.0" +version = "1.6.4" description = "WebSocket client for Python with low level API options" optional = false python-versions = ">=3.8" files = [ - {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, - {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, + {file = "websocket-client-1.6.4.tar.gz", hash = "sha256:b3324019b3c28572086c4a319f91d1dcd44e6e11cd340232978c684a7650d0df"}, + {file = "websocket_client-1.6.4-py3-none-any.whl", hash = "sha256:084072e0a7f5f347ef2ac3d8698a5e0b4ffbfcab607628cadabc650fc9a83a24"}, ] [package.extras] -docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx-rtd-theme (>=1.1.0)"] +docs = ["Sphinx (>=6.0)", "sphinx-rtd-theme (>=1.1.0)"] optional = ["python-socks", "wsaccel"] test = ["websockets"] [[package]] name = "websockets" -version = "13.1" +version = "11.0.3" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee"}, - {file = "websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7"}, - {file = "websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa"}, - {file = "websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0"}, - {file = "websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f"}, - {file = "websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe"}, - {file = "websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19"}, - {file = "websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5"}, - {file = "websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7"}, - {file = "websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3"}, - {file = "websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9"}, - {file = "websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f"}, - {file = "websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc"}, - {file = "websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49"}, - {file = "websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6"}, - {file = "websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14"}, - {file = "websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf"}, - {file = "websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c"}, - {file = "websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6"}, - {file = "websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708"}, - {file = "websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f"}, - {file = "websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2"}, - {file = "websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6"}, - {file = "websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d"}, - {file = "websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d"}, - {file = "websockets-13.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23"}, - {file = "websockets-13.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7"}, - {file = "websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295"}, - {file = "websockets-13.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96"}, - {file = "websockets-13.1-cp38-cp38-win32.whl", hash = "sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf"}, - {file = "websockets-13.1-cp38-cp38-win_amd64.whl", hash = "sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d"}, - {file = "websockets-13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7"}, - {file = "websockets-13.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa"}, - {file = "websockets-13.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6"}, - {file = "websockets-13.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5"}, - {file = "websockets-13.1-cp39-cp39-win32.whl", hash = "sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c"}, - {file = "websockets-13.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238"}, - {file = "websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6"}, - {file = "websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a"}, - {file = "websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b"}, - {file = "websockets-13.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d"}, - {file = "websockets-13.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027"}, - {file = "websockets-13.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e"}, - {file = "websockets-13.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb"}, - {file = "websockets-13.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20"}, - {file = "websockets-13.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678"}, - {file = "websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f"}, - {file = "websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878"}, + {file = "websockets-11.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac"}, + {file = "websockets-11.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d"}, + {file = "websockets-11.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11"}, + {file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4"}, + {file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526"}, + {file = "websockets-11.0.3-cp310-cp310-win32.whl", hash = "sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69"}, + {file = "websockets-11.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288"}, + {file = "websockets-11.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b"}, + {file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf"}, + {file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd"}, + {file = "websockets-11.0.3-cp311-cp311-win32.whl", hash = "sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c"}, + {file = "websockets-11.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8"}, + {file = "websockets-11.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9f59a3c656fef341a99e3d63189852be7084c0e54b75734cde571182c087b152"}, + {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2529338a6ff0eb0b50c7be33dc3d0e456381157a31eefc561771ee431134a97f"}, + {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34fd59a4ac42dff6d4681d8843217137f6bc85ed29722f2f7222bd619d15e95b"}, + {file = "websockets-11.0.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:332d126167ddddec94597c2365537baf9ff62dfcc9db4266f263d455f2f031cb"}, + {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6505c1b31274723ccaf5f515c1824a4ad2f0d191cec942666b3d0f3aa4cb4007"}, + {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f467ba0050b7de85016b43f5a22b46383ef004c4f672148a8abf32bc999a87f0"}, + {file = "websockets-11.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9d9acd80072abcc98bd2c86c3c9cd4ac2347b5a5a0cae7ed5c0ee5675f86d9af"}, + {file = "websockets-11.0.3-cp37-cp37m-win32.whl", hash = "sha256:e590228200fcfc7e9109509e4d9125eace2042fd52b595dd22bbc34bb282307f"}, + {file = "websockets-11.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:b16fff62b45eccb9c7abb18e60e7e446998093cdcb50fed33134b9b6878836de"}, + {file = "websockets-11.0.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fb06eea71a00a7af0ae6aefbb932fb8a7df3cb390cc217d51a9ad7343de1b8d0"}, + {file = "websockets-11.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8a34e13a62a59c871064dfd8ffb150867e54291e46d4a7cf11d02c94a5275bae"}, + {file = "websockets-11.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4841ed00f1026dfbced6fca7d963c4e7043aa832648671b5138008dc5a8f6d99"}, + {file = "websockets-11.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a073fc9ab1c8aff37c99f11f1641e16da517770e31a37265d2755282a5d28aa"}, + {file = "websockets-11.0.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68b977f21ce443d6d378dbd5ca38621755f2063d6fdb3335bda981d552cfff86"}, + {file = "websockets-11.0.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a99a7a71631f0efe727c10edfba09ea6bee4166a6f9c19aafb6c0b5917d09c"}, + {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bee9fcb41db2a23bed96c6b6ead6489702c12334ea20a297aa095ce6d31370d0"}, + {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4b253869ea05a5a073ebfdcb5cb3b0266a57c3764cf6fe114e4cd90f4bfa5f5e"}, + {file = "websockets-11.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1553cb82942b2a74dd9b15a018dce645d4e68674de2ca31ff13ebc2d9f283788"}, + {file = "websockets-11.0.3-cp38-cp38-win32.whl", hash = "sha256:f61bdb1df43dc9c131791fbc2355535f9024b9a04398d3bd0684fc16ab07df74"}, + {file = "websockets-11.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:03aae4edc0b1c68498f41a6772d80ac7c1e33c06c6ffa2ac1c27a07653e79d6f"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:777354ee16f02f643a4c7f2b3eff8027a33c9861edc691a2003531f5da4f6bc8"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8c82f11964f010053e13daafdc7154ce7385ecc538989a354ccc7067fd7028fd"}, + {file = "websockets-11.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3580dd9c1ad0701169e4d6fc41e878ffe05e6bdcaf3c412f9d559389d0c9e016"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f1a3f10f836fab6ca6efa97bb952300b20ae56b409414ca85bff2ad241d2a61"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df41b9bc27c2c25b486bae7cf42fccdc52ff181c8c387bfd026624a491c2671b"}, + {file = "websockets-11.0.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279e5de4671e79a9ac877427f4ac4ce93751b8823f276b681d04b2156713b9dd"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1fdf26fa8a6a592f8f9235285b8affa72748dc12e964a5518c6c5e8f916716f7"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69269f3a0b472e91125b503d3c0b3566bda26da0a3261c49f0027eb6075086d1"}, + {file = "websockets-11.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:97b52894d948d2f6ea480171a27122d77af14ced35f62e5c892ca2fae9344311"}, + {file = "websockets-11.0.3-cp39-cp39-win32.whl", hash = "sha256:c7f3cb904cce8e1be667c7e6fef4516b98d1a6a0635a58a57528d577ac18a128"}, + {file = "websockets-11.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c792ea4eabc0159535608fc5658a74d1a81020eb35195dd63214dcf07556f67e"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b"}, + {file = "websockets-11.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280"}, + {file = "websockets-11.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4"}, + {file = "websockets-11.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602"}, + {file = "websockets-11.0.3-py3-none-any.whl", hash = "sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6"}, + {file = "websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"}, ] -[[package]] -name = "xattr" -version = "1.1.4" -description = "Python wrapper for extended filesystem attributes" -optional = false -python-versions = ">=3.8" -files = [ - {file = "xattr-1.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:acb85b6249e9f3ea10cbb56df1021d43f4027212f0d004304bc9075dc7f54769"}, - {file = "xattr-1.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1a848ab125c0fafdc501ccd83b4c9018bba576a037a4ca5960a22f39e295552e"}, - {file = "xattr-1.1.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:467ee77471d26ae5187ee7081b82175b5ca56ead4b71467ec2e6119d1b08beed"}, - {file = "xattr-1.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fd35f46cb0154f7033f9d5d0960f226857acb0d1e0d71fd7af18ed84663007c"}, - {file = "xattr-1.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d956478e9bb98a1efd20ebc6e5703497c1d2d690d5a13c4df4abf59881eed50"}, - {file = "xattr-1.1.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f25dfdcd974b700fb04a40e14a664a80227ee58e02ea062ac241f0d7dc54b4e"}, - {file = "xattr-1.1.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33b63365c1fcbc80a79f601575bac0d6921732e0245b776876f3db3fcfefe22d"}, - {file = "xattr-1.1.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:544542be95c9b49e211f0a463758f200de88ba6d5a94d3c4f42855a484341acd"}, - {file = "xattr-1.1.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac14c9893f3ea046784b7702be30889b200d31adcd2e6781a8a190b6423f9f2d"}, - {file = "xattr-1.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bb4bbe37ba95542081890dd34fa5347bef4651e276647adaa802d5d0d7d86452"}, - {file = "xattr-1.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3da489ecef798705f9a39ea8cea4ead0d1eeed55f92c345add89740bd930bab6"}, - {file = "xattr-1.1.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:798dd0cbe696635a6f74b06fc430818bf9c3b24314e1502eadf67027ab60c9b0"}, - {file = "xattr-1.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2b6361626efad5eb5a6bf8172c6c67339e09397ee8140ec41258737bea9681"}, - {file = "xattr-1.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7fa20a0c9ce022d19123b1c5b848d00a68b837251835a7929fe041ee81dcd0"}, - {file = "xattr-1.1.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e20eeb08e2c57fc7e71f050b1cfae35cbb46105449853a582bf53fd23c5379e"}, - {file = "xattr-1.1.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:477370e75821bded901487e5e752cffe554d1bd3bd4839b627d4d1ee8c95a093"}, - {file = "xattr-1.1.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a8682091cd34a9f4a93c8aaea4101aae99f1506e24da00a3cc3dd2eca9566f21"}, - {file = "xattr-1.1.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2e079b3b1a274ba2121cf0da38bbe5c8d2fb1cc49ecbceb395ce20eb7d69556d"}, - {file = "xattr-1.1.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ae6579dea05bf9f335a082f711d5924a98da563cac72a2d550f5b940c401c0e9"}, - {file = "xattr-1.1.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd6038ec9df2e67af23c212693751481d5f7e858156924f14340376c48ed9ac7"}, - {file = "xattr-1.1.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:608b2877526674eb15df4150ef4b70b7b292ae00e65aecaae2f192af224be200"}, - {file = "xattr-1.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54dad1a6a998c6a23edfd25e99f4d38e9b942d54e518570044edf8c767687ea"}, - {file = "xattr-1.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0dab6ff72bb2b508f3850c368f8e53bd706585012676e1f71debba3310acde8"}, - {file = "xattr-1.1.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a3c54c6af7cf09432b2c461af257d5f4b1cb2d59eee045f91bacef44421a46d"}, - {file = "xattr-1.1.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e346e05a158d554639fbf7a0db169dc693c2d2260c7acb3239448f1ff4a9d67f"}, - {file = "xattr-1.1.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3ff6d9e2103d0d6e5fcd65b85a2005b66ea81c0720a37036445faadc5bbfa424"}, - {file = "xattr-1.1.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7a2ee4563c6414dfec0d1ac610f59d39d5220531ae06373eeb1a06ee37cd193f"}, - {file = "xattr-1.1.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878df1b38cfdadf3184ad8c7b0f516311128d5597b60ac0b3486948953658a83"}, - {file = "xattr-1.1.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c9b8350244a1c5454f93a8d572628ff71d7e2fc2f7480dcf4c4f0e8af3150fe"}, - {file = "xattr-1.1.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a46bf48fb662b8bd745b78bef1074a1e08f41a531168de62b5d7bd331dadb11a"}, - {file = "xattr-1.1.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83fc3c07b583777b1dda6355329f75ca6b7179fe0d1002f1afe0ef96f7e3b5de"}, - {file = "xattr-1.1.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6308b19cff71441513258699f0538394fad5d66e1d324635207a97cb076fd439"}, - {file = "xattr-1.1.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48c00ddc15ddadc9c729cd9504dabf50adb3d9c28f647d4ac9a3df45a046b1a0"}, - {file = "xattr-1.1.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a06136196f26293758e1b244200b73156a0274af9a7349fa201c71c7af3bb9e8"}, - {file = "xattr-1.1.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8fc2631a3c6cfcdc71f7f0f847461839963754e76a2015de71e7e71e3304abc0"}, - {file = "xattr-1.1.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d6e1e835f9c938d129dd45e7eb52ebf7d2d6816323dab93ce311bf331f7d2328"}, - {file = "xattr-1.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:60dea2d369a6484e8b7136224fc2971e10e2c46340d83ab780924afe78c90066"}, - {file = "xattr-1.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:85c2b778b09d919523f80f244d799a142302582d76da18903dc693207c4020b0"}, - {file = "xattr-1.1.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ee0abba9e1b890d39141714ff43e9666864ca635ea8a5a2194d989e6b17fe862"}, - {file = "xattr-1.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e4174ba7f51f46b95ea7918d907c91cd579575d59e6a2f22ca36a0551026737"}, - {file = "xattr-1.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2b05e52e99d82d87528c54c2c5c8c5fb0ba435f85ac6545511aeea136e49925"}, - {file = "xattr-1.1.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a3696fad746be37de34eb73c60ea67144162bd08106a5308a90ce9dea9a3287"}, - {file = "xattr-1.1.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a3a7149439a26b68904c14fdc4587cde4ac7d80303e9ff0fefcfd893b698c976"}, - {file = "xattr-1.1.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:507b36a126ce900dbfa35d4e2c2db92570c933294cba5d161ecd6a89f7b52f43"}, - {file = "xattr-1.1.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9392b417b54923e031041940d396b1d709df1d3779c6744454e1f1c1f4dad4f5"}, - {file = "xattr-1.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e9f00315e6c02943893b77f544776b49c756ac76960bea7cb8d7e1b96aefc284"}, - {file = "xattr-1.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c8f98775065260140efb348b1ff8d50fd66ddcbf0c685b76eb1e87b380aaffb3"}, - {file = "xattr-1.1.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b471c6a515f434a167ca16c5c15ff34ee42d11956baa749173a8a4e385ff23e7"}, - {file = "xattr-1.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee0763a1b7ceb78ba2f78bee5f30d1551dc26daafcce4ac125115fa1def20519"}, - {file = "xattr-1.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:099e6e9ce7999b403d36d9cf943105a3d25d8233486b54ec9d1b78623b050433"}, - {file = "xattr-1.1.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e56faef9dde8d969f0d646fb6171883693f88ae39163ecd919ec707fbafa85"}, - {file = "xattr-1.1.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:328156d4e594c9ae63e1072503c168849e601a153ad37f0290743544332d6b6f"}, - {file = "xattr-1.1.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a57a55a27c7864d6916344c9a91776afda6c3b8b2209f8a69b79cdba93fbe128"}, - {file = "xattr-1.1.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3c19cdde08b040df1e99d2500bf8a9cff775ab0e6fa162bf8afe6d84aa93ed04"}, - {file = "xattr-1.1.4-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c72667f19d3a9acf324aed97f58861d398d87e42314731e7c6ab3ac7850c971"}, - {file = "xattr-1.1.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:67ae934d75ea2563fc48a27c5945749575c74a6de19fdd38390917ddcb0e4f24"}, - {file = "xattr-1.1.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1b0c348dd8523554dc535540d2046c0c8a535bb086561d8359f3667967b6ca"}, - {file = "xattr-1.1.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22284255d2a8e8f3da195bd8e8d43ce674dbc7c38d38cb6ecfb37fae7755d31f"}, - {file = "xattr-1.1.4-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b38aac5ef4381c26d3ce147ca98fba5a78b1e5bcd6be6755b4908659f2705c6d"}, - {file = "xattr-1.1.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:803f864af528f6f763a5be1e7b1ccab418e55ae0e4abc8bda961d162f850c991"}, - {file = "xattr-1.1.4-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:40354ebfb5cecd60a5fbb9833a8a452d147486b0ffec547823658556625d98b5"}, - {file = "xattr-1.1.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2abaf5d06be3361bfa8e0db2ee123ba8e92beab5bceed5e9d7847f2145a32e04"}, - {file = "xattr-1.1.4-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e638e5ffedc3565242b5fa3296899d35161bad771f88d66277b58f03a1ba9fe"}, - {file = "xattr-1.1.4-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0597e919d116ec39997804288d77bec3777228368efc0f2294b84a527fc4f9c2"}, - {file = "xattr-1.1.4-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee9455c501d19f065527afda974418b3ef7c61e85d9519d122cd6eb3cb7a00"}, - {file = "xattr-1.1.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:89ed62ce430f5789e15cfc1ccabc172fd8b349c3a17c52d9e6c64ecedf08c265"}, - {file = "xattr-1.1.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e25b824f4b9259cd8bb6e83c4873cf8bf080f6e4fa034a02fe778e07aba8d345"}, - {file = "xattr-1.1.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8fba66faa0016dfc0af3dd7ac5782b5786a1dfb851f9f3455e266f94c2a05a04"}, - {file = "xattr-1.1.4-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ec4b0c3e0a7bcd103f3cf31dd40c349940b2d4223ce43d384a3548992138ef1"}, - {file = "xattr-1.1.4.tar.gz", hash = "sha256:b7b02ecb2270da5b7e7deaeea8f8b528c17368401c2b9d5f63e91f545b45d372"}, -] - -[package.dependencies] -cffi = ">=1.16.0" - -[package.extras] -test = ["pytest"] - [[package]] name = "xmltodict" -version = "0.14.2" +version = "0.13.0" description = "Makes working with XML feel like you are working with JSON" optional = false -python-versions = ">=3.6" +python-versions = ">=3.4" files = [ - {file = "xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac"}, - {file = "xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553"}, + {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, + {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, ] [[package]] @@ -2707,26 +1700,7 @@ mutagen = "*" pycryptodomex = "*" websockets = "*" -[[package]] -name = "zipp" -version = "3.20.2" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.8" -files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] -type = ["pytest-mypy"] - [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "3e35149e73c237381b87aa360390154341cf8dcd84a45219e0c9c743fef46686" +content-hash = "88e1c8ab21ed3b415db6cd4f112055ed8dc22cf96fa9ba5ef6b396154499dff1" diff --git a/pyproject.toml b/pyproject.toml index 8857f7b..c1b14a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ beautifulsoup4 = "~4.8.2" click = "^8.0.1" cffi = "^1.16.0" coloredlogs = "^15.0" -construct = "2.8.8" +construct = "2.10.70" crccheck = "^1.0" cryptography = "^43.0.3" ecpy = "^1.2.5" @@ -26,28 +26,23 @@ langcodes = { extras = ["data"], version = "^3.1.0" } lxml = "^4.6.3" m3u8 = "^0.9.0" marisa-trie = "^1.1.0" -poetry = "1.8.5" pproxy = "^2.7.7" -protobuf3 = { path = "./scripts/protobuf3", develop = true } +protobuf = "^3.13.0" pycaption = "^2.1.1" pycryptodome = "^3.21.0" pycryptodomex = "^3.4.3" pyhulu = "^1.1.2" pymediainfo = "^5.0.3" PyMySQL = { extras = ["rsa"], version = "^1.0.2" } -pymp4 = "^1.4.0" -pyplayready = { path = "./scripts/pyplayready", develop = true } -pywidevine = { path = "./scripts/pywidevine", develop = true } pysubs2 = "^1.6.1" PyYAML = "^6.0.1" -requests = { extras = ["socks"], version = "2.32.3" } +requests = { extras = ["socks"], version = "2.29.0" } tldextract = "^3.1.0" toml = "^0.10.2" -tqdm = "^4.67.0" Unidecode = "^1.2.0" validators = "^0.18.2" websocket-client = "^1.1.0" -xmltodict = "^0.14.0" +xmltodict = "^0.13.0" yt-dlp = "^2022.11.11" [tool.poetry.dev-dependencies] diff --git a/scripts/GetVikiManifestFree.py b/scripts/GetVikiManifestFree.py index 48fa620..32d5182 100644 --- a/scripts/GetVikiManifestFree.py +++ b/scripts/GetVikiManifestFree.py @@ -13,13 +13,13 @@ http.headers.update({ }) # get player fragment page fragment = http.get(sys.argv[1].replace("/videos/", "/player5_fragment/")).text -# get encrypted manifest.xml urls for both hls and dash +# get encrypted manifest urls for both hls and dash encrypted_manifests = {k: bytes.fromhex(re.findall( r' 0: - _Deprecated.count -= 1 - warnings.warn( - 'Call to deprecated create function %s(). Note: Create unlinked ' - 'descriptors is going to go away. Please use get/find descriptors from ' - 'generated code or query the descriptor_pool.' - % name, - category=DeprecationWarning, stacklevel=3) - - -# Deprecated warnings will print 100 times at most which should be enough for -# users to notice and do not cause timeout. -_Deprecated.count = 100 - - -_internal_create_key = object() - - -class DescriptorBase(metaclass=DescriptorMetaclass): - - """Descriptors base class. - - This class is the base of all descriptor classes. It provides common options - related functionality. - - Attributes: - has_options: True if the descriptor has non-default options. Usually it - is not necessary to read this -- just call GetOptions() which will - happily return the default instance. However, it's sometimes useful - for efficiency, and also useful inside the protobuf implementation to - avoid some bootstrapping issues. - """ - - if _USE_C_DESCRIPTORS: - # The class, or tuple of classes, that are considered as "virtual - # subclasses" of this descriptor class. - _C_DESCRIPTOR_CLASS = () - - def __init__(self, options, serialized_options, options_class_name): - """Initialize the descriptor given its options message and the name of the - class of the options message. The name of the class is required in case - the options message is None and has to be created. - """ - self._options = options - self._options_class_name = options_class_name - self._serialized_options = serialized_options - - # Does this descriptor have non-default options? - self.has_options = (options is not None) or (serialized_options is not None) - - def _SetOptions(self, options, options_class_name): - """Sets the descriptor's options - - This function is used in generated proto2 files to update descriptor - options. It must not be used outside proto2. - """ - self._options = options - self._options_class_name = options_class_name - - # Does this descriptor have non-default options? - self.has_options = options is not None - - def GetOptions(self): - """Retrieves descriptor options. - - This method returns the options set or creates the default options for the - descriptor. - """ - if self._options: - return self._options - - from google.protobuf import descriptor_pb2 - try: - options_class = getattr(descriptor_pb2, - self._options_class_name) - except AttributeError: - raise RuntimeError('Unknown options class name %s!' % - (self._options_class_name)) - - with _lock: - if self._serialized_options is None: - self._options = options_class() - else: - self._options = _ParseOptions(options_class(), - self._serialized_options) - - return self._options - - -class _NestedDescriptorBase(DescriptorBase): - """Common class for descriptors that can be nested.""" - - def __init__(self, options, options_class_name, name, full_name, - file, containing_type, serialized_start=None, - serialized_end=None, serialized_options=None): - """Constructor. - - Args: - options: Protocol message options or None - to use default message options. - options_class_name (str): The class name of the above options. - name (str): Name of this protocol message type. - full_name (str): Fully-qualified name of this protocol message type, - which will include protocol "package" name and the name of any - enclosing types. - file (FileDescriptor): Reference to file info. - containing_type: if provided, this is a nested descriptor, with this - descriptor as parent, otherwise None. - serialized_start: The start index (inclusive) in block in the - file.serialized_pb that describes this descriptor. - serialized_end: The end index (exclusive) in block in the - file.serialized_pb that describes this descriptor. - serialized_options: Protocol message serialized options or None. - """ - super(_NestedDescriptorBase, self).__init__( - options, serialized_options, options_class_name) - - self.name = name - # TODO(falk): Add function to calculate full_name instead of having it in - # memory? - self.full_name = full_name - self.file = file - self.containing_type = containing_type - - self._serialized_start = serialized_start - self._serialized_end = serialized_end - - def CopyToProto(self, proto): - """Copies this to the matching proto in descriptor_pb2. - - Args: - proto: An empty proto instance from descriptor_pb2. - - Raises: - Error: If self couldn't be serialized, due to to few constructor - arguments. - """ - if (self.file is not None and - self._serialized_start is not None and - self._serialized_end is not None): - proto.ParseFromString(self.file.serialized_pb[ - self._serialized_start:self._serialized_end]) - else: - raise Error('Descriptor does not contain serialization.') - - -class Descriptor(_NestedDescriptorBase): - - """Descriptor for a protocol message type. - - Attributes: - name (str): Name of this protocol message type. - full_name (str): Fully-qualified name of this protocol message type, - which will include protocol "package" name and the name of any - enclosing types. - containing_type (Descriptor): Reference to the descriptor of the type - containing us, or None if this is top-level. - fields (list[FieldDescriptor]): Field descriptors for all fields in - this type. - fields_by_number (dict(int, FieldDescriptor)): Same - :class:`FieldDescriptor` objects as in :attr:`fields`, but indexed - by "number" attribute in each FieldDescriptor. - fields_by_name (dict(str, FieldDescriptor)): Same - :class:`FieldDescriptor` objects as in :attr:`fields`, but indexed by - "name" attribute in each :class:`FieldDescriptor`. - nested_types (list[Descriptor]): Descriptor references - for all protocol message types nested within this one. - nested_types_by_name (dict(str, Descriptor)): Same Descriptor - objects as in :attr:`nested_types`, but indexed by "name" attribute - in each Descriptor. - enum_types (list[EnumDescriptor]): :class:`EnumDescriptor` references - for all enums contained within this type. - enum_types_by_name (dict(str, EnumDescriptor)): Same - :class:`EnumDescriptor` objects as in :attr:`enum_types`, but - indexed by "name" attribute in each EnumDescriptor. - enum_values_by_name (dict(str, EnumValueDescriptor)): Dict mapping - from enum value name to :class:`EnumValueDescriptor` for that value. - extensions (list[FieldDescriptor]): All extensions defined directly - within this message type (NOT within a nested type). - extensions_by_name (dict(str, FieldDescriptor)): Same FieldDescriptor - objects as :attr:`extensions`, but indexed by "name" attribute of each - FieldDescriptor. - is_extendable (bool): Does this type define any extension ranges? - oneofs (list[OneofDescriptor]): The list of descriptors for oneof fields - in this message. - oneofs_by_name (dict(str, OneofDescriptor)): Same objects as in - :attr:`oneofs`, but indexed by "name" attribute. - file (FileDescriptor): Reference to file descriptor. - - """ - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.Descriptor - - def __new__( - cls, - name=None, - full_name=None, - filename=None, - containing_type=None, - fields=None, - nested_types=None, - enum_types=None, - extensions=None, - options=None, - serialized_options=None, - is_extendable=True, - extension_ranges=None, - oneofs=None, - file=None, # pylint: disable=redefined-builtin - serialized_start=None, - serialized_end=None, - syntax=None, - create_key=None): - _message.Message._CheckCalledFromGeneratedFile() - return _message.default_pool.FindMessageTypeByName(full_name) - - # NOTE(tmarek): The file argument redefining a builtin is nothing we can - # fix right now since we don't know how many clients already rely on the - # name of the argument. - def __init__(self, name, full_name, filename, containing_type, fields, - nested_types, enum_types, extensions, options=None, - serialized_options=None, - is_extendable=True, extension_ranges=None, oneofs=None, - file=None, serialized_start=None, serialized_end=None, # pylint: disable=redefined-builtin - syntax=None, create_key=None): - """Arguments to __init__() are as described in the description - of Descriptor fields above. - - Note that filename is an obsolete argument, that is not used anymore. - Please use file.name to access this as an attribute. - """ - if create_key is not _internal_create_key: - _Deprecated('Descriptor') - - super(Descriptor, self).__init__( - options, 'MessageOptions', name, full_name, file, - containing_type, serialized_start=serialized_start, - serialized_end=serialized_end, serialized_options=serialized_options) - - # We have fields in addition to fields_by_name and fields_by_number, - # so that: - # 1. Clients can index fields by "order in which they're listed." - # 2. Clients can easily iterate over all fields with the terse - # syntax: for f in descriptor.fields: ... - self.fields = fields - for field in self.fields: - field.containing_type = self - self.fields_by_number = dict((f.number, f) for f in fields) - self.fields_by_name = dict((f.name, f) for f in fields) - self._fields_by_camelcase_name = None - - self.nested_types = nested_types - for nested_type in nested_types: - nested_type.containing_type = self - self.nested_types_by_name = dict((t.name, t) for t in nested_types) - - self.enum_types = enum_types - for enum_type in self.enum_types: - enum_type.containing_type = self - self.enum_types_by_name = dict((t.name, t) for t in enum_types) - self.enum_values_by_name = dict( - (v.name, v) for t in enum_types for v in t.values) - - self.extensions = extensions - for extension in self.extensions: - extension.extension_scope = self - self.extensions_by_name = dict((f.name, f) for f in extensions) - self.is_extendable = is_extendable - self.extension_ranges = extension_ranges - self.oneofs = oneofs if oneofs is not None else [] - self.oneofs_by_name = dict((o.name, o) for o in self.oneofs) - for oneof in self.oneofs: - oneof.containing_type = self - self.syntax = syntax or "proto2" - - @property - def fields_by_camelcase_name(self): - """Same FieldDescriptor objects as in :attr:`fields`, but indexed by - :attr:`FieldDescriptor.camelcase_name`. - """ - if self._fields_by_camelcase_name is None: - self._fields_by_camelcase_name = dict( - (f.camelcase_name, f) for f in self.fields) - return self._fields_by_camelcase_name - - def EnumValueName(self, enum, value): - """Returns the string name of an enum value. - - This is just a small helper method to simplify a common operation. - - Args: - enum: string name of the Enum. - value: int, value of the enum. - - Returns: - string name of the enum value. - - Raises: - KeyError if either the Enum doesn't exist or the value is not a valid - value for the enum. - """ - return self.enum_types_by_name[enum].values_by_number[value].name - - def CopyToProto(self, proto): - """Copies this to a descriptor_pb2.DescriptorProto. - - Args: - proto: An empty descriptor_pb2.DescriptorProto. - """ - # This function is overridden to give a better doc comment. - super(Descriptor, self).CopyToProto(proto) - - -# TODO(robinson): We should have aggressive checking here, -# for example: -# * If you specify a repeated field, you should not be allowed -# to specify a default value. -# * [Other examples here as needed]. -# -# TODO(robinson): for this and other *Descriptor classes, we -# might also want to lock things down aggressively (e.g., -# prevent clients from setting the attributes). Having -# stronger invariants here in general will reduce the number -# of runtime checks we must do in reflection.py... -class FieldDescriptor(DescriptorBase): - - """Descriptor for a single field in a .proto file. - - Attributes: - name (str): Name of this field, exactly as it appears in .proto. - full_name (str): Name of this field, including containing scope. This is - particularly relevant for extensions. - index (int): Dense, 0-indexed index giving the order that this - field textually appears within its message in the .proto file. - number (int): Tag number declared for this field in the .proto file. - - type (int): (One of the TYPE_* constants below) Declared type. - cpp_type (int): (One of the CPPTYPE_* constants below) C++ type used to - represent this field. - - label (int): (One of the LABEL_* constants below) Tells whether this - field is optional, required, or repeated. - has_default_value (bool): True if this field has a default value defined, - otherwise false. - default_value (Varies): Default value of this field. Only - meaningful for non-repeated scalar fields. Repeated fields - should always set this to [], and non-repeated composite - fields should always set this to None. - - containing_type (Descriptor): Descriptor of the protocol message - type that contains this field. Set by the Descriptor constructor - if we're passed into one. - Somewhat confusingly, for extension fields, this is the - descriptor of the EXTENDED message, not the descriptor - of the message containing this field. (See is_extension and - extension_scope below). - message_type (Descriptor): If a composite field, a descriptor - of the message type contained in this field. Otherwise, this is None. - enum_type (EnumDescriptor): If this field contains an enum, a - descriptor of that enum. Otherwise, this is None. - - is_extension: True iff this describes an extension field. - extension_scope (Descriptor): Only meaningful if is_extension is True. - Gives the message that immediately contains this extension field. - Will be None iff we're a top-level (file-level) extension field. - - options (descriptor_pb2.FieldOptions): Protocol message field options or - None to use default field options. - - containing_oneof (OneofDescriptor): If the field is a member of a oneof - union, contains its descriptor. Otherwise, None. - - file (FileDescriptor): Reference to file descriptor. - """ - - # Must be consistent with C++ FieldDescriptor::Type enum in - # descriptor.h. - # - # TODO(robinson): Find a way to eliminate this repetition. - TYPE_DOUBLE = 1 - TYPE_FLOAT = 2 - TYPE_INT64 = 3 - TYPE_UINT64 = 4 - TYPE_INT32 = 5 - TYPE_FIXED64 = 6 - TYPE_FIXED32 = 7 - TYPE_BOOL = 8 - TYPE_STRING = 9 - TYPE_GROUP = 10 - TYPE_MESSAGE = 11 - TYPE_BYTES = 12 - TYPE_UINT32 = 13 - TYPE_ENUM = 14 - TYPE_SFIXED32 = 15 - TYPE_SFIXED64 = 16 - TYPE_SINT32 = 17 - TYPE_SINT64 = 18 - MAX_TYPE = 18 - - # Must be consistent with C++ FieldDescriptor::CppType enum in - # descriptor.h. - # - # TODO(robinson): Find a way to eliminate this repetition. - CPPTYPE_INT32 = 1 - CPPTYPE_INT64 = 2 - CPPTYPE_UINT32 = 3 - CPPTYPE_UINT64 = 4 - CPPTYPE_DOUBLE = 5 - CPPTYPE_FLOAT = 6 - CPPTYPE_BOOL = 7 - CPPTYPE_ENUM = 8 - CPPTYPE_STRING = 9 - CPPTYPE_MESSAGE = 10 - MAX_CPPTYPE = 10 - - _PYTHON_TO_CPP_PROTO_TYPE_MAP = { - TYPE_DOUBLE: CPPTYPE_DOUBLE, - TYPE_FLOAT: CPPTYPE_FLOAT, - TYPE_ENUM: CPPTYPE_ENUM, - TYPE_INT64: CPPTYPE_INT64, - TYPE_SINT64: CPPTYPE_INT64, - TYPE_SFIXED64: CPPTYPE_INT64, - TYPE_UINT64: CPPTYPE_UINT64, - TYPE_FIXED64: CPPTYPE_UINT64, - TYPE_INT32: CPPTYPE_INT32, - TYPE_SFIXED32: CPPTYPE_INT32, - TYPE_SINT32: CPPTYPE_INT32, - TYPE_UINT32: CPPTYPE_UINT32, - TYPE_FIXED32: CPPTYPE_UINT32, - TYPE_BYTES: CPPTYPE_STRING, - TYPE_STRING: CPPTYPE_STRING, - TYPE_BOOL: CPPTYPE_BOOL, - TYPE_MESSAGE: CPPTYPE_MESSAGE, - TYPE_GROUP: CPPTYPE_MESSAGE - } - - # Must be consistent with C++ FieldDescriptor::Label enum in - # descriptor.h. - # - # TODO(robinson): Find a way to eliminate this repetition. - LABEL_OPTIONAL = 1 - LABEL_REQUIRED = 2 - LABEL_REPEATED = 3 - MAX_LABEL = 3 - - # Must be consistent with C++ constants kMaxNumber, kFirstReservedNumber, - # and kLastReservedNumber in descriptor.h - MAX_FIELD_NUMBER = (1 << 29) - 1 - FIRST_RESERVED_FIELD_NUMBER = 19000 - LAST_RESERVED_FIELD_NUMBER = 19999 - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.FieldDescriptor - - def __new__(cls, name, full_name, index, number, type, cpp_type, label, - default_value, message_type, enum_type, containing_type, - is_extension, extension_scope, options=None, - serialized_options=None, - has_default_value=True, containing_oneof=None, json_name=None, - file=None, create_key=None): # pylint: disable=redefined-builtin - _message.Message._CheckCalledFromGeneratedFile() - if is_extension: - return _message.default_pool.FindExtensionByName(full_name) - else: - return _message.default_pool.FindFieldByName(full_name) - - def __init__(self, name, full_name, index, number, type, cpp_type, label, - default_value, message_type, enum_type, containing_type, - is_extension, extension_scope, options=None, - serialized_options=None, - has_default_value=True, containing_oneof=None, json_name=None, - file=None, create_key=None): # pylint: disable=redefined-builtin - """The arguments are as described in the description of FieldDescriptor - attributes above. - - Note that containing_type may be None, and may be set later if necessary - (to deal with circular references between message types, for example). - Likewise for extension_scope. - """ - if create_key is not _internal_create_key: - _Deprecated('FieldDescriptor') - - super(FieldDescriptor, self).__init__( - options, serialized_options, 'FieldOptions') - self.name = name - self.full_name = full_name - self.file = file - self._camelcase_name = None - if json_name is None: - self.json_name = _ToJsonName(name) - else: - self.json_name = json_name - self.index = index - self.number = number - self.type = type - self.cpp_type = cpp_type - self.label = label - self.has_default_value = has_default_value - self.default_value = default_value - self.containing_type = containing_type - self.message_type = message_type - self.enum_type = enum_type - self.is_extension = is_extension - self.extension_scope = extension_scope - self.containing_oneof = containing_oneof - if api_implementation.Type() == 'cpp': - if is_extension: - self._cdescriptor = _message.default_pool.FindExtensionByName(full_name) - else: - self._cdescriptor = _message.default_pool.FindFieldByName(full_name) - else: - self._cdescriptor = None - - @property - def camelcase_name(self): - """Camelcase name of this field. - - Returns: - str: the name in CamelCase. - """ - if self._camelcase_name is None: - self._camelcase_name = _ToCamelCase(self.name) - return self._camelcase_name - - @property - def has_presence(self): - """Whether the field distinguishes between unpopulated and default values. - - Raises: - RuntimeError: singular field that is not linked with message nor file. - """ - if self.label == FieldDescriptor.LABEL_REPEATED: - return False - if (self.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE or - self.containing_oneof): - return True - if hasattr(self.file, 'syntax'): - return self.file.syntax == 'proto2' - if hasattr(self.message_type, 'syntax'): - return self.message_type.syntax == 'proto2' - raise RuntimeError( - 'has_presence is not ready to use because field %s is not' - ' linked with message type nor file' % self.full_name) - - @staticmethod - def ProtoTypeToCppProtoType(proto_type): - """Converts from a Python proto type to a C++ Proto Type. - - The Python ProtocolBuffer classes specify both the 'Python' datatype and the - 'C++' datatype - and they're not the same. This helper method should - translate from one to another. - - Args: - proto_type: the Python proto type (descriptor.FieldDescriptor.TYPE_*) - Returns: - int: descriptor.FieldDescriptor.CPPTYPE_*, the C++ type. - Raises: - TypeTransformationError: when the Python proto type isn't known. - """ - try: - return FieldDescriptor._PYTHON_TO_CPP_PROTO_TYPE_MAP[proto_type] - except KeyError: - raise TypeTransformationError('Unknown proto_type: %s' % proto_type) - - -class EnumDescriptor(_NestedDescriptorBase): - - """Descriptor for an enum defined in a .proto file. - - Attributes: - name (str): Name of the enum type. - full_name (str): Full name of the type, including package name - and any enclosing type(s). - - values (list[EnumValueDescriptor]): List of the values - in this enum. - values_by_name (dict(str, EnumValueDescriptor)): Same as :attr:`values`, - but indexed by the "name" field of each EnumValueDescriptor. - values_by_number (dict(int, EnumValueDescriptor)): Same as :attr:`values`, - but indexed by the "number" field of each EnumValueDescriptor. - containing_type (Descriptor): Descriptor of the immediate containing - type of this enum, or None if this is an enum defined at the - top level in a .proto file. Set by Descriptor's constructor - if we're passed into one. - file (FileDescriptor): Reference to file descriptor. - options (descriptor_pb2.EnumOptions): Enum options message or - None to use default enum options. - """ - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.EnumDescriptor - - def __new__(cls, name, full_name, filename, values, - containing_type=None, options=None, - serialized_options=None, file=None, # pylint: disable=redefined-builtin - serialized_start=None, serialized_end=None, create_key=None): - _message.Message._CheckCalledFromGeneratedFile() - return _message.default_pool.FindEnumTypeByName(full_name) - - def __init__(self, name, full_name, filename, values, - containing_type=None, options=None, - serialized_options=None, file=None, # pylint: disable=redefined-builtin - serialized_start=None, serialized_end=None, create_key=None): - """Arguments are as described in the attribute description above. - - Note that filename is an obsolete argument, that is not used anymore. - Please use file.name to access this as an attribute. - """ - if create_key is not _internal_create_key: - _Deprecated('EnumDescriptor') - - super(EnumDescriptor, self).__init__( - options, 'EnumOptions', name, full_name, file, - containing_type, serialized_start=serialized_start, - serialized_end=serialized_end, serialized_options=serialized_options) - - self.values = values - for value in self.values: - value.type = self - self.values_by_name = dict((v.name, v) for v in values) - # Values are reversed to ensure that the first alias is retained. - self.values_by_number = dict((v.number, v) for v in reversed(values)) - - def CopyToProto(self, proto): - """Copies this to a descriptor_pb2.EnumDescriptorProto. - - Args: - proto (descriptor_pb2.EnumDescriptorProto): An empty descriptor proto. - """ - # This function is overridden to give a better doc comment. - super(EnumDescriptor, self).CopyToProto(proto) - - -class EnumValueDescriptor(DescriptorBase): - - """Descriptor for a single value within an enum. - - Attributes: - name (str): Name of this value. - index (int): Dense, 0-indexed index giving the order that this - value appears textually within its enum in the .proto file. - number (int): Actual number assigned to this enum value. - type (EnumDescriptor): :class:`EnumDescriptor` to which this value - belongs. Set by :class:`EnumDescriptor`'s constructor if we're - passed into one. - options (descriptor_pb2.EnumValueOptions): Enum value options message or - None to use default enum value options options. - """ - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.EnumValueDescriptor - - def __new__(cls, name, index, number, - type=None, # pylint: disable=redefined-builtin - options=None, serialized_options=None, create_key=None): - _message.Message._CheckCalledFromGeneratedFile() - # There is no way we can build a complete EnumValueDescriptor with the - # given parameters (the name of the Enum is not known, for example). - # Fortunately generated files just pass it to the EnumDescriptor() - # constructor, which will ignore it, so returning None is good enough. - return None - - def __init__(self, name, index, number, - type=None, # pylint: disable=redefined-builtin - options=None, serialized_options=None, create_key=None): - """Arguments are as described in the attribute description above.""" - if create_key is not _internal_create_key: - _Deprecated('EnumValueDescriptor') - - super(EnumValueDescriptor, self).__init__( - options, serialized_options, 'EnumValueOptions') - self.name = name - self.index = index - self.number = number - self.type = type - - -class OneofDescriptor(DescriptorBase): - """Descriptor for a oneof field. - - Attributes: - name (str): Name of the oneof field. - full_name (str): Full name of the oneof field, including package name. - index (int): 0-based index giving the order of the oneof field inside - its containing type. - containing_type (Descriptor): :class:`Descriptor` of the protocol message - type that contains this field. Set by the :class:`Descriptor` constructor - if we're passed into one. - fields (list[FieldDescriptor]): The list of field descriptors this - oneof can contain. - """ - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.OneofDescriptor - - def __new__( - cls, name, full_name, index, containing_type, fields, options=None, - serialized_options=None, create_key=None): - _message.Message._CheckCalledFromGeneratedFile() - return _message.default_pool.FindOneofByName(full_name) - - def __init__( - self, name, full_name, index, containing_type, fields, options=None, - serialized_options=None, create_key=None): - """Arguments are as described in the attribute description above.""" - if create_key is not _internal_create_key: - _Deprecated('OneofDescriptor') - - super(OneofDescriptor, self).__init__( - options, serialized_options, 'OneofOptions') - self.name = name - self.full_name = full_name - self.index = index - self.containing_type = containing_type - self.fields = fields - - -class ServiceDescriptor(_NestedDescriptorBase): - - """Descriptor for a service. - - Attributes: - name (str): Name of the service. - full_name (str): Full name of the service, including package name. - index (int): 0-indexed index giving the order that this services - definition appears within the .proto file. - methods (list[MethodDescriptor]): List of methods provided by this - service. - methods_by_name (dict(str, MethodDescriptor)): Same - :class:`MethodDescriptor` objects as in :attr:`methods_by_name`, but - indexed by "name" attribute in each :class:`MethodDescriptor`. - options (descriptor_pb2.ServiceOptions): Service options message or - None to use default service options. - file (FileDescriptor): Reference to file info. - """ - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.ServiceDescriptor - - def __new__( - cls, - name=None, - full_name=None, - index=None, - methods=None, - options=None, - serialized_options=None, - file=None, # pylint: disable=redefined-builtin - serialized_start=None, - serialized_end=None, - create_key=None): - _message.Message._CheckCalledFromGeneratedFile() # pylint: disable=protected-access - return _message.default_pool.FindServiceByName(full_name) - - def __init__(self, name, full_name, index, methods, options=None, - serialized_options=None, file=None, # pylint: disable=redefined-builtin - serialized_start=None, serialized_end=None, create_key=None): - if create_key is not _internal_create_key: - _Deprecated('ServiceDescriptor') - - super(ServiceDescriptor, self).__init__( - options, 'ServiceOptions', name, full_name, file, - None, serialized_start=serialized_start, - serialized_end=serialized_end, serialized_options=serialized_options) - self.index = index - self.methods = methods - self.methods_by_name = dict((m.name, m) for m in methods) - # Set the containing service for each method in this service. - for method in self.methods: - method.containing_service = self - - def FindMethodByName(self, name): - """Searches for the specified method, and returns its descriptor. - - Args: - name (str): Name of the method. - Returns: - MethodDescriptor or None: the descriptor for the requested method, if - found. - """ - return self.methods_by_name.get(name, None) - - def CopyToProto(self, proto): - """Copies this to a descriptor_pb2.ServiceDescriptorProto. - - Args: - proto (descriptor_pb2.ServiceDescriptorProto): An empty descriptor proto. - """ - # This function is overridden to give a better doc comment. - super(ServiceDescriptor, self).CopyToProto(proto) - - -class MethodDescriptor(DescriptorBase): - - """Descriptor for a method in a service. - - Attributes: - name (str): Name of the method within the service. - full_name (str): Full name of method. - index (int): 0-indexed index of the method inside the service. - containing_service (ServiceDescriptor): The service that contains this - method. - input_type (Descriptor): The descriptor of the message that this method - accepts. - output_type (Descriptor): The descriptor of the message that this method - returns. - client_streaming (bool): Whether this method uses client streaming. - server_streaming (bool): Whether this method uses server streaming. - options (descriptor_pb2.MethodOptions or None): Method options message, or - None to use default method options. - """ - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.MethodDescriptor - - def __new__(cls, - name, - full_name, - index, - containing_service, - input_type, - output_type, - client_streaming=False, - server_streaming=False, - options=None, - serialized_options=None, - create_key=None): - _message.Message._CheckCalledFromGeneratedFile() # pylint: disable=protected-access - return _message.default_pool.FindMethodByName(full_name) - - def __init__(self, - name, - full_name, - index, - containing_service, - input_type, - output_type, - client_streaming=False, - server_streaming=False, - options=None, - serialized_options=None, - create_key=None): - """The arguments are as described in the description of MethodDescriptor - attributes above. - - Note that containing_service may be None, and may be set later if necessary. - """ - if create_key is not _internal_create_key: - _Deprecated('MethodDescriptor') - - super(MethodDescriptor, self).__init__( - options, serialized_options, 'MethodOptions') - self.name = name - self.full_name = full_name - self.index = index - self.containing_service = containing_service - self.input_type = input_type - self.output_type = output_type - self.client_streaming = client_streaming - self.server_streaming = server_streaming - - def CopyToProto(self, proto): - """Copies this to a descriptor_pb2.MethodDescriptorProto. - - Args: - proto (descriptor_pb2.MethodDescriptorProto): An empty descriptor proto. - - Raises: - Error: If self couldn't be serialized, due to too few constructor - arguments. - """ - if self.containing_service is not None: - from google.protobuf import descriptor_pb2 - service_proto = descriptor_pb2.ServiceDescriptorProto() - self.containing_service.CopyToProto(service_proto) - proto.CopyFrom(service_proto.method[self.index]) - else: - raise Error('Descriptor does not contain a service.') - - -class FileDescriptor(DescriptorBase): - """Descriptor for a file. Mimics the descriptor_pb2.FileDescriptorProto. - - Note that :attr:`enum_types_by_name`, :attr:`extensions_by_name`, and - :attr:`dependencies` fields are only set by the - :py:mod:`google.protobuf.message_factory` module, and not by the generated - proto code. - - Attributes: - name (str): Name of file, relative to root of source tree. - package (str): Name of the package - syntax (str): string indicating syntax of the file (can be "proto2" or - "proto3") - serialized_pb (bytes): Byte string of serialized - :class:`descriptor_pb2.FileDescriptorProto`. - dependencies (list[FileDescriptor]): List of other :class:`FileDescriptor` - objects this :class:`FileDescriptor` depends on. - public_dependencies (list[FileDescriptor]): A subset of - :attr:`dependencies`, which were declared as "public". - message_types_by_name (dict(str, Descriptor)): Mapping from message names - to their :class:`Descriptor`. - enum_types_by_name (dict(str, EnumDescriptor)): Mapping from enum names to - their :class:`EnumDescriptor`. - extensions_by_name (dict(str, FieldDescriptor)): Mapping from extension - names declared at file scope to their :class:`FieldDescriptor`. - services_by_name (dict(str, ServiceDescriptor)): Mapping from services' - names to their :class:`ServiceDescriptor`. - pool (DescriptorPool): The pool this descriptor belongs to. When not - passed to the constructor, the global default pool is used. - """ - - if _USE_C_DESCRIPTORS: - _C_DESCRIPTOR_CLASS = _message.FileDescriptor - - def __new__(cls, name, package, options=None, - serialized_options=None, serialized_pb=None, - dependencies=None, public_dependencies=None, - syntax=None, pool=None, create_key=None): - # FileDescriptor() is called from various places, not only from generated - # files, to register dynamic proto files and messages. - # pylint: disable=g-explicit-bool-comparison - if serialized_pb == b'': - # Cpp generated code must be linked in if serialized_pb is '' - try: - return _message.default_pool.FindFileByName(name) - except KeyError: - raise RuntimeError('Please link in cpp generated lib for %s' % (name)) - elif serialized_pb: - return _message.default_pool.AddSerializedFile(serialized_pb) - else: - return super(FileDescriptor, cls).__new__(cls) - - def __init__(self, name, package, options=None, - serialized_options=None, serialized_pb=None, - dependencies=None, public_dependencies=None, - syntax=None, pool=None, create_key=None): - """Constructor.""" - if create_key is not _internal_create_key: - _Deprecated('FileDescriptor') - - super(FileDescriptor, self).__init__( - options, serialized_options, 'FileOptions') - - if pool is None: - from google.protobuf import descriptor_pool - pool = descriptor_pool.Default() - self.pool = pool - self.message_types_by_name = {} - self.name = name - self.package = package - self.syntax = syntax or "proto2" - self.serialized_pb = serialized_pb - - self.enum_types_by_name = {} - self.extensions_by_name = {} - self.services_by_name = {} - self.dependencies = (dependencies or []) - self.public_dependencies = (public_dependencies or []) - - def CopyToProto(self, proto): - """Copies this to a descriptor_pb2.FileDescriptorProto. - - Args: - proto: An empty descriptor_pb2.FileDescriptorProto. - """ - proto.ParseFromString(self.serialized_pb) - - -def _ParseOptions(message, string): - """Parses serialized options. - - This helper function is used to parse serialized options in generated - proto2 files. It must not be used outside proto2. - """ - message.ParseFromString(string) - return message - - -def _ToCamelCase(name): - """Converts name to camel-case and returns it.""" - capitalize_next = False - result = [] - - for c in name: - if c == '_': - if result: - capitalize_next = True - elif capitalize_next: - result.append(c.upper()) - capitalize_next = False - else: - result += c - - # Lower-case the first letter. - if result and result[0].isupper(): - result[0] = result[0].lower() - return ''.join(result) - - -def _OptionsOrNone(descriptor_proto): - """Returns the value of the field `options`, or None if it is not set.""" - if descriptor_proto.HasField('options'): - return descriptor_proto.options - else: - return None - - -def _ToJsonName(name): - """Converts name to Json name and returns it.""" - capitalize_next = False - result = [] - - for c in name: - if c == '_': - capitalize_next = True - elif capitalize_next: - result.append(c.upper()) - capitalize_next = False - else: - result += c - - return ''.join(result) - - -def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True, - syntax=None): - """Make a protobuf Descriptor given a DescriptorProto protobuf. - - Handles nested descriptors. Note that this is limited to the scope of defining - a message inside of another message. Composite fields can currently only be - resolved if the message is defined in the same scope as the field. - - Args: - desc_proto: The descriptor_pb2.DescriptorProto protobuf message. - package: Optional package name for the new message Descriptor (string). - build_file_if_cpp: Update the C++ descriptor pool if api matches. - Set to False on recursion, so no duplicates are created. - syntax: The syntax/semantics that should be used. Set to "proto3" to get - proto3 field presence semantics. - Returns: - A Descriptor for protobuf messages. - """ - if api_implementation.Type() == 'cpp' and build_file_if_cpp: - # The C++ implementation requires all descriptors to be backed by the same - # definition in the C++ descriptor pool. To do this, we build a - # FileDescriptorProto with the same definition as this descriptor and build - # it into the pool. - from google.protobuf import descriptor_pb2 - file_descriptor_proto = descriptor_pb2.FileDescriptorProto() - file_descriptor_proto.message_type.add().MergeFrom(desc_proto) - - # Generate a random name for this proto file to prevent conflicts with any - # imported ones. We need to specify a file name so the descriptor pool - # accepts our FileDescriptorProto, but it is not important what that file - # name is actually set to. - proto_name = binascii.hexlify(os.urandom(16)).decode('ascii') - - if package: - file_descriptor_proto.name = os.path.join(package.replace('.', '/'), - proto_name + '.proto') - file_descriptor_proto.package = package - else: - file_descriptor_proto.name = proto_name + '.proto' - - _message.default_pool.Add(file_descriptor_proto) - result = _message.default_pool.FindFileByName(file_descriptor_proto.name) - - if _USE_C_DESCRIPTORS: - return result.message_types_by_name[desc_proto.name] - - full_message_name = [desc_proto.name] - if package: full_message_name.insert(0, package) - - # Create Descriptors for enum types - enum_types = {} - for enum_proto in desc_proto.enum_type: - full_name = '.'.join(full_message_name + [enum_proto.name]) - enum_desc = EnumDescriptor( - enum_proto.name, full_name, None, [ - EnumValueDescriptor(enum_val.name, ii, enum_val.number, - create_key=_internal_create_key) - for ii, enum_val in enumerate(enum_proto.value)], - create_key=_internal_create_key) - enum_types[full_name] = enum_desc - - # Create Descriptors for nested types - nested_types = {} - for nested_proto in desc_proto.nested_type: - full_name = '.'.join(full_message_name + [nested_proto.name]) - # Nested types are just those defined inside of the message, not all types - # used by fields in the message, so no loops are possible here. - nested_desc = MakeDescriptor(nested_proto, - package='.'.join(full_message_name), - build_file_if_cpp=False, - syntax=syntax) - nested_types[full_name] = nested_desc - - fields = [] - for field_proto in desc_proto.field: - full_name = '.'.join(full_message_name + [field_proto.name]) - enum_desc = None - nested_desc = None - if field_proto.json_name: - json_name = field_proto.json_name - else: - json_name = None - if field_proto.HasField('type_name'): - type_name = field_proto.type_name - full_type_name = '.'.join(full_message_name + - [type_name[type_name.rfind('.')+1:]]) - if full_type_name in nested_types: - nested_desc = nested_types[full_type_name] - elif full_type_name in enum_types: - enum_desc = enum_types[full_type_name] - # Else type_name references a non-local type, which isn't implemented - field = FieldDescriptor( - field_proto.name, full_name, field_proto.number - 1, - field_proto.number, field_proto.type, - FieldDescriptor.ProtoTypeToCppProtoType(field_proto.type), - field_proto.label, None, nested_desc, enum_desc, None, False, None, - options=_OptionsOrNone(field_proto), has_default_value=False, - json_name=json_name, create_key=_internal_create_key) - fields.append(field) - - desc_name = '.'.join(full_message_name) - return Descriptor(desc_proto.name, desc_name, None, None, fields, - list(nested_types.values()), list(enum_types.values()), [], - options=_OptionsOrNone(desc_proto), - create_key=_internal_create_key) diff --git a/scripts/protobuf3/protobuf3/descriptor_database.py b/scripts/protobuf3/protobuf3/descriptor_database.py deleted file mode 100644 index 073eddc..0000000 --- a/scripts/protobuf3/protobuf3/descriptor_database.py +++ /dev/null @@ -1,177 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Provides a container for DescriptorProtos.""" - -__author__ = 'matthewtoia@google.com (Matt Toia)' - -import warnings - - -class Error(Exception): - pass - - -class DescriptorDatabaseConflictingDefinitionError(Error): - """Raised when a proto is added with the same name & different descriptor.""" - - -class DescriptorDatabase(object): - """A container accepting FileDescriptorProtos and maps DescriptorProtos.""" - - def __init__(self): - self._file_desc_protos_by_file = {} - self._file_desc_protos_by_symbol = {} - - def Add(self, file_desc_proto): - """Adds the FileDescriptorProto and its types to this database. - - Args: - file_desc_proto: The FileDescriptorProto to add. - Raises: - DescriptorDatabaseConflictingDefinitionError: if an attempt is made to - add a proto with the same name but different definition than an - existing proto in the database. - """ - proto_name = file_desc_proto.name - if proto_name not in self._file_desc_protos_by_file: - self._file_desc_protos_by_file[proto_name] = file_desc_proto - elif self._file_desc_protos_by_file[proto_name] != file_desc_proto: - raise DescriptorDatabaseConflictingDefinitionError( - '%s already added, but with different descriptor.' % proto_name) - else: - return - - # Add all the top-level descriptors to the index. - package = file_desc_proto.package - for message in file_desc_proto.message_type: - for name in _ExtractSymbols(message, package): - self._AddSymbol(name, file_desc_proto) - for enum in file_desc_proto.enum_type: - self._AddSymbol(('.'.join((package, enum.name))), file_desc_proto) - for enum_value in enum.value: - self._file_desc_protos_by_symbol[ - '.'.join((package, enum_value.name))] = file_desc_proto - for extension in file_desc_proto.extension: - self._AddSymbol(('.'.join((package, extension.name))), file_desc_proto) - for service in file_desc_proto.service: - self._AddSymbol(('.'.join((package, service.name))), file_desc_proto) - - def FindFileByName(self, name): - """Finds the file descriptor proto by file name. - - Typically the file name is a relative path ending to a .proto file. The - proto with the given name will have to have been added to this database - using the Add method or else an error will be raised. - - Args: - name: The file name to find. - - Returns: - The file descriptor proto matching the name. - - Raises: - KeyError if no file by the given name was added. - """ - - return self._file_desc_protos_by_file[name] - - def FindFileContainingSymbol(self, symbol): - """Finds the file descriptor proto containing the specified symbol. - - The symbol should be a fully qualified name including the file descriptor's - package and any containing messages. Some examples: - - 'some.package.name.Message' - 'some.package.name.Message.NestedEnum' - 'some.package.name.Message.some_field' - - The file descriptor proto containing the specified symbol must be added to - this database using the Add method or else an error will be raised. - - Args: - symbol: The fully qualified symbol name. - - Returns: - The file descriptor proto containing the symbol. - - Raises: - KeyError if no file contains the specified symbol. - """ - try: - return self._file_desc_protos_by_symbol[symbol] - except KeyError: - # Fields, enum values, and nested extensions are not in - # _file_desc_protos_by_symbol. Try to find the top level - # descriptor. Non-existent nested symbol under a valid top level - # descriptor can also be found. The behavior is the same with - # protobuf C++. - top_level, _, _ = symbol.rpartition('.') - try: - return self._file_desc_protos_by_symbol[top_level] - except KeyError: - # Raise the original symbol as a KeyError for better diagnostics. - raise KeyError(symbol) - - def FindFileContainingExtension(self, extendee_name, extension_number): - # TODO(jieluo): implement this API. - return None - - def FindAllExtensionNumbers(self, extendee_name): - # TODO(jieluo): implement this API. - return [] - - def _AddSymbol(self, name, file_desc_proto): - if name in self._file_desc_protos_by_symbol: - warn_msg = ('Conflict register for file "' + file_desc_proto.name + - '": ' + name + - ' is already defined in file "' + - self._file_desc_protos_by_symbol[name].name + '"') - warnings.warn(warn_msg, RuntimeWarning) - self._file_desc_protos_by_symbol[name] = file_desc_proto - - -def _ExtractSymbols(desc_proto, package): - """Pulls out all the symbols from a descriptor proto. - - Args: - desc_proto: The proto to extract symbols from. - package: The package containing the descriptor type. - - Yields: - The fully qualified name found in the descriptor. - """ - message_name = package + '.' + desc_proto.name if package else desc_proto.name - yield message_name - for nested_type in desc_proto.nested_type: - for symbol in _ExtractSymbols(nested_type, message_name): - yield symbol - for enum_type in desc_proto.enum_type: - yield '.'.join((message_name, enum_type.name)) diff --git a/scripts/protobuf3/protobuf3/descriptor_pb2.py b/scripts/protobuf3/protobuf3/descriptor_pb2.py deleted file mode 100644 index f570386..0000000 --- a/scripts/protobuf3/protobuf3/descriptor_pb2.py +++ /dev/null @@ -1,1925 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/descriptor.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR = _descriptor.FileDescriptor( - name='google/protobuf/descriptor.proto', - package='google.protobuf', - syntax='proto2', - serialized_options=None, - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n google/protobuf/descriptor.proto\x12\x0fgoogle.protobuf\"G\n\x11\x46ileDescriptorSet\x12\x32\n\x04\x66ile\x18\x01 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\"\xdb\x03\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12\x36\n\x0cmessage_type\x18\x04 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x05 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12\x38\n\x07service\x18\x06 \x03(\x0b\x32\'.google.protobuf.ServiceDescriptorProto\x12\x38\n\textension\x18\x07 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12-\n\x07options\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.FileOptions\x12\x39\n\x10source_code_info\x18\t \x01(\x0b\x32\x1f.google.protobuf.SourceCodeInfo\x12\x0e\n\x06syntax\x18\x0c \x01(\t\"\xa9\x05\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x34\n\x05\x66ield\x18\x02 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x38\n\textension\x18\x06 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x35\n\x0bnested_type\x18\x03 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x04 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12H\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32/.google.protobuf.DescriptorProto.ExtensionRange\x12\x39\n\noneof_decl\x18\x08 \x03(\x0b\x32%.google.protobuf.OneofDescriptorProto\x12\x30\n\x07options\x18\x07 \x01(\x0b\x32\x1f.google.protobuf.MessageOptions\x12\x46\n\x0ereserved_range\x18\t \x03(\x0b\x32..google.protobuf.DescriptorProto.ReservedRange\x12\x15\n\rreserved_name\x18\n \x03(\t\x1a\x65\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\x12\x37\n\x07options\x18\x03 \x01(\x0b\x32&.google.protobuf.ExtensionRangeOptions\x1a+\n\rReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"g\n\x15\x45xtensionRangeOptions\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xd5\x05\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12:\n\x05label\x18\x04 \x01(\x0e\x32+.google.protobuf.FieldDescriptorProto.Label\x12\x38\n\x04type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12\x13\n\x0boneof_index\x18\t \x01(\x05\x12\x11\n\tjson_name\x18\n \x01(\t\x12.\n\x07options\x18\x08 \x01(\x0b\x32\x1d.google.protobuf.FieldOptions\x12\x17\n\x0fproto3_optional\x18\x11 \x01(\x08\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\x12\x12\n\x0eLABEL_REPEATED\x10\x03\"T\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12.\n\x07options\x18\x02 \x01(\x0b\x32\x1d.google.protobuf.OneofOptions\"\xa4\x02\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x03(\x0b\x32).google.protobuf.EnumValueDescriptorProto\x12-\n\x07options\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.EnumOptions\x12N\n\x0ereserved_range\x18\x04 \x03(\x0b\x32\x36.google.protobuf.EnumDescriptorProto.EnumReservedRange\x12\x15\n\rreserved_name\x18\x05 \x03(\t\x1a/\n\x11\x45numReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"l\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12\x32\n\x07options\x18\x03 \x01(\x0b\x32!.google.protobuf.EnumValueOptions\"\x90\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06method\x18\x02 \x03(\x0b\x32&.google.protobuf.MethodDescriptorProto\x12\x30\n\x07options\x18\x03 \x01(\x0b\x32\x1f.google.protobuf.ServiceOptions\"\xc1\x01\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12/\n\x07options\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.MethodOptions\x12\x1f\n\x10\x63lient_streaming\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10server_streaming\x18\x06 \x01(\x08:\x05\x66\x61lse\"\xa5\x06\n\x0b\x46ileOptions\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12)\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08\x42\x02\x18\x01\x12%\n\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x46\n\x0coptimize_for\x18\t \x01(\x0e\x32).google.protobuf.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12#\n\x14php_generic_services\x18* \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x10\x63\x63_enable_arenas\x18\x1f \x01(\x08:\x04true\x12\x19\n\x11objc_class_prefix\x18$ \x01(\t\x12\x18\n\x10\x63sharp_namespace\x18% \x01(\t\x12\x14\n\x0cswift_prefix\x18\' \x01(\t\x12\x18\n\x10php_class_prefix\x18( \x01(\t\x12\x15\n\rphp_namespace\x18) \x01(\t\x12\x1e\n\x16php_metadata_namespace\x18, \x01(\t\x12\x14\n\x0cruby_package\x18- \x01(\t\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08&\x10\'\"\x84\x02\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07J\x04\x08\x08\x10\tJ\x04\x08\t\x10\n\"\xbe\x03\n\x0c\x46ieldOptions\x12:\n\x05\x63type\x18\x01 \x01(\x0e\x32#.google.protobuf.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12?\n\x06jstype\x18\x06 \x01(\x0e\x32$.google.protobuf.FieldOptions.JSType:\tJS_NORMAL\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0funverified_lazy\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"5\n\x06JSType\x12\r\n\tJS_NORMAL\x10\x00\x12\r\n\tJS_STRING\x10\x01\x12\r\n\tJS_NUMBER\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05\"^\n\x0cOneofOptions\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x93\x01\n\x0b\x45numOptions\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x05\x10\x06\"}\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"{\n\x0eServiceOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xad\x02\n\rMethodOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12_\n\x11idempotency_level\x18\" \x01(\x0e\x32/.google.protobuf.MethodOptions.IdempotencyLevel:\x13IDEMPOTENCY_UNKNOWN\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"P\n\x10IdempotencyLevel\x12\x17\n\x13IDEMPOTENCY_UNKNOWN\x10\x00\x12\x13\n\x0fNO_SIDE_EFFECTS\x10\x01\x12\x0e\n\nIDEMPOTENT\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x02\n\x13UninterpretedOption\x12;\n\x04name\x18\x02 \x03(\x0b\x32-.google.protobuf.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"\xd5\x01\n\x0eSourceCodeInfo\x12:\n\x08location\x18\x01 \x03(\x0b\x32(.google.protobuf.SourceCodeInfo.Location\x1a\x86\x01\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\t\x12!\n\x19leading_detached_comments\x18\x06 \x03(\t\"\xa7\x01\n\x11GeneratedCodeInfo\x12\x41\n\nannotation\x18\x01 \x03(\x0b\x32-.google.protobuf.GeneratedCodeInfo.Annotation\x1aO\n\nAnnotation\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x13\n\x0bsource_file\x18\x02 \x01(\t\x12\r\n\x05\x62\x65gin\x18\x03 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x04 \x01(\x05\x42~\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01Z-google.golang.org/protobuf/types/descriptorpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1aGoogle.Protobuf.Reflection' - ) -else: - DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n google/protobuf/descriptor.proto\x12\x0fgoogle.protobuf\"G\n\x11\x46ileDescriptorSet\x12\x32\n\x04\x66ile\x18\x01 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\"\xdb\x03\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12\x36\n\x0cmessage_type\x18\x04 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x05 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12\x38\n\x07service\x18\x06 \x03(\x0b\x32\'.google.protobuf.ServiceDescriptorProto\x12\x38\n\textension\x18\x07 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12-\n\x07options\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.FileOptions\x12\x39\n\x10source_code_info\x18\t \x01(\x0b\x32\x1f.google.protobuf.SourceCodeInfo\x12\x0e\n\x06syntax\x18\x0c \x01(\t\"\xa9\x05\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x34\n\x05\x66ield\x18\x02 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x38\n\textension\x18\x06 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x35\n\x0bnested_type\x18\x03 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x04 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12H\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32/.google.protobuf.DescriptorProto.ExtensionRange\x12\x39\n\noneof_decl\x18\x08 \x03(\x0b\x32%.google.protobuf.OneofDescriptorProto\x12\x30\n\x07options\x18\x07 \x01(\x0b\x32\x1f.google.protobuf.MessageOptions\x12\x46\n\x0ereserved_range\x18\t \x03(\x0b\x32..google.protobuf.DescriptorProto.ReservedRange\x12\x15\n\rreserved_name\x18\n \x03(\t\x1a\x65\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\x12\x37\n\x07options\x18\x03 \x01(\x0b\x32&.google.protobuf.ExtensionRangeOptions\x1a+\n\rReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"g\n\x15\x45xtensionRangeOptions\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xd5\x05\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12:\n\x05label\x18\x04 \x01(\x0e\x32+.google.protobuf.FieldDescriptorProto.Label\x12\x38\n\x04type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12\x13\n\x0boneof_index\x18\t \x01(\x05\x12\x11\n\tjson_name\x18\n \x01(\t\x12.\n\x07options\x18\x08 \x01(\x0b\x32\x1d.google.protobuf.FieldOptions\x12\x17\n\x0fproto3_optional\x18\x11 \x01(\x08\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\x12\x12\n\x0eLABEL_REPEATED\x10\x03\"T\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12.\n\x07options\x18\x02 \x01(\x0b\x32\x1d.google.protobuf.OneofOptions\"\xa4\x02\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x03(\x0b\x32).google.protobuf.EnumValueDescriptorProto\x12-\n\x07options\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.EnumOptions\x12N\n\x0ereserved_range\x18\x04 \x03(\x0b\x32\x36.google.protobuf.EnumDescriptorProto.EnumReservedRange\x12\x15\n\rreserved_name\x18\x05 \x03(\t\x1a/\n\x11\x45numReservedRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"l\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12\x32\n\x07options\x18\x03 \x01(\x0b\x32!.google.protobuf.EnumValueOptions\"\x90\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06method\x18\x02 \x03(\x0b\x32&.google.protobuf.MethodDescriptorProto\x12\x30\n\x07options\x18\x03 \x01(\x0b\x32\x1f.google.protobuf.ServiceOptions\"\xc1\x01\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12/\n\x07options\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.MethodOptions\x12\x1f\n\x10\x63lient_streaming\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10server_streaming\x18\x06 \x01(\x08:\x05\x66\x61lse\"\xa5\x06\n\x0b\x46ileOptions\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12)\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08\x42\x02\x18\x01\x12%\n\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x46\n\x0coptimize_for\x18\t \x01(\x0e\x32).google.protobuf.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12#\n\x14php_generic_services\x18* \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x10\x63\x63_enable_arenas\x18\x1f \x01(\x08:\x04true\x12\x19\n\x11objc_class_prefix\x18$ \x01(\t\x12\x18\n\x10\x63sharp_namespace\x18% \x01(\t\x12\x14\n\x0cswift_prefix\x18\' \x01(\t\x12\x18\n\x10php_class_prefix\x18( \x01(\t\x12\x15\n\rphp_namespace\x18) \x01(\t\x12\x1e\n\x16php_metadata_namespace\x18, \x01(\t\x12\x14\n\x0cruby_package\x18- \x01(\t\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08&\x10\'\"\x84\x02\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07J\x04\x08\x08\x10\tJ\x04\x08\t\x10\n\"\xbe\x03\n\x0c\x46ieldOptions\x12:\n\x05\x63type\x18\x01 \x01(\x0e\x32#.google.protobuf.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12?\n\x06jstype\x18\x06 \x01(\x0e\x32$.google.protobuf.FieldOptions.JSType:\tJS_NORMAL\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0funverified_lazy\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02\"5\n\x06JSType\x12\r\n\tJS_NORMAL\x10\x00\x12\r\n\tJS_STRING\x10\x01\x12\r\n\tJS_NUMBER\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x04\x10\x05\"^\n\x0cOneofOptions\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x93\x01\n\x0b\x45numOptions\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02J\x04\x08\x05\x10\x06\"}\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"{\n\x0eServiceOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xad\x02\n\rMethodOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12_\n\x11idempotency_level\x18\" \x01(\x0e\x32/.google.protobuf.MethodOptions.IdempotencyLevel:\x13IDEMPOTENCY_UNKNOWN\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"P\n\x10IdempotencyLevel\x12\x17\n\x13IDEMPOTENCY_UNKNOWN\x10\x00\x12\x13\n\x0fNO_SIDE_EFFECTS\x10\x01\x12\x0e\n\nIDEMPOTENT\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x02\n\x13UninterpretedOption\x12;\n\x04name\x18\x02 \x03(\x0b\x32-.google.protobuf.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"\xd5\x01\n\x0eSourceCodeInfo\x12:\n\x08location\x18\x01 \x03(\x0b\x32(.google.protobuf.SourceCodeInfo.Location\x1a\x86\x01\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\t\x12!\n\x19leading_detached_comments\x18\x06 \x03(\t\"\xa7\x01\n\x11GeneratedCodeInfo\x12\x41\n\nannotation\x18\x01 \x03(\x0b\x32-.google.protobuf.GeneratedCodeInfo.Annotation\x1aO\n\nAnnotation\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x13\n\x0bsource_file\x18\x02 \x01(\t\x12\r\n\x05\x62\x65gin\x18\x03 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x04 \x01(\x05\x42~\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01Z-google.golang.org/protobuf/types/descriptorpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1aGoogle.Protobuf.Reflection') - -if _descriptor._USE_C_DESCRIPTORS == False: - _FIELDDESCRIPTORPROTO_TYPE = _descriptor.EnumDescriptor( - name='Type', - full_name='google.protobuf.FieldDescriptorProto.Type', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='TYPE_DOUBLE', index=0, number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_FLOAT', index=1, number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_INT64', index=2, number=3, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_UINT64', index=3, number=4, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_INT32', index=4, number=5, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_FIXED64', index=5, number=6, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_FIXED32', index=6, number=7, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_BOOL', index=7, number=8, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_STRING', index=8, number=9, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_GROUP', index=9, number=10, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_MESSAGE', index=10, number=11, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_BYTES', index=11, number=12, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_UINT32', index=12, number=13, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_ENUM', index=13, number=14, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_SFIXED32', index=14, number=15, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_SFIXED64', index=15, number=16, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_SINT32', index=16, number=17, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='TYPE_SINT64', index=17, number=18, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - ) - _sym_db.RegisterEnumDescriptor(_FIELDDESCRIPTORPROTO_TYPE) - - _FIELDDESCRIPTORPROTO_LABEL = _descriptor.EnumDescriptor( - name='Label', - full_name='google.protobuf.FieldDescriptorProto.Label', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='LABEL_OPTIONAL', index=0, number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='LABEL_REQUIRED', index=1, number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='LABEL_REPEATED', index=2, number=3, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - ) - _sym_db.RegisterEnumDescriptor(_FIELDDESCRIPTORPROTO_LABEL) - - _FILEOPTIONS_OPTIMIZEMODE = _descriptor.EnumDescriptor( - name='OptimizeMode', - full_name='google.protobuf.FileOptions.OptimizeMode', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='SPEED', index=0, number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='CODE_SIZE', index=1, number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='LITE_RUNTIME', index=2, number=3, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - ) - _sym_db.RegisterEnumDescriptor(_FILEOPTIONS_OPTIMIZEMODE) - - _FIELDOPTIONS_CTYPE = _descriptor.EnumDescriptor( - name='CType', - full_name='google.protobuf.FieldOptions.CType', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='STRING', index=0, number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='CORD', index=1, number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='STRING_PIECE', index=2, number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - ) - _sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_CTYPE) - - _FIELDOPTIONS_JSTYPE = _descriptor.EnumDescriptor( - name='JSType', - full_name='google.protobuf.FieldOptions.JSType', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='JS_NORMAL', index=0, number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='JS_STRING', index=1, number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='JS_NUMBER', index=2, number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - ) - _sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_JSTYPE) - - _METHODOPTIONS_IDEMPOTENCYLEVEL = _descriptor.EnumDescriptor( - name='IdempotencyLevel', - full_name='google.protobuf.MethodOptions.IdempotencyLevel', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='IDEMPOTENCY_UNKNOWN', index=0, number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='NO_SIDE_EFFECTS', index=1, number=1, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='IDEMPOTENT', index=2, number=2, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - ) - _sym_db.RegisterEnumDescriptor(_METHODOPTIONS_IDEMPOTENCYLEVEL) - - - _FILEDESCRIPTORSET = _descriptor.Descriptor( - name='FileDescriptorSet', - full_name='google.protobuf.FileDescriptorSet', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='file', full_name='google.protobuf.FileDescriptorSet.file', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _FILEDESCRIPTORPROTO = _descriptor.Descriptor( - name='FileDescriptorProto', - full_name='google.protobuf.FileDescriptorProto', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.FileDescriptorProto.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='package', full_name='google.protobuf.FileDescriptorProto.package', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='dependency', full_name='google.protobuf.FileDescriptorProto.dependency', index=2, - number=3, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='public_dependency', full_name='google.protobuf.FileDescriptorProto.public_dependency', index=3, - number=10, type=5, cpp_type=1, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='weak_dependency', full_name='google.protobuf.FileDescriptorProto.weak_dependency', index=4, - number=11, type=5, cpp_type=1, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='message_type', full_name='google.protobuf.FileDescriptorProto.message_type', index=5, - number=4, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='enum_type', full_name='google.protobuf.FileDescriptorProto.enum_type', index=6, - number=5, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='service', full_name='google.protobuf.FileDescriptorProto.service', index=7, - number=6, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='extension', full_name='google.protobuf.FileDescriptorProto.extension', index=8, - number=7, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.FileDescriptorProto.options', index=9, - number=8, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='source_code_info', full_name='google.protobuf.FileDescriptorProto.source_code_info', index=10, - number=9, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='syntax', full_name='google.protobuf.FileDescriptorProto.syntax', index=11, - number=12, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _DESCRIPTORPROTO_EXTENSIONRANGE = _descriptor.Descriptor( - name='ExtensionRange', - full_name='google.protobuf.DescriptorProto.ExtensionRange', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='start', full_name='google.protobuf.DescriptorProto.ExtensionRange.start', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='end', full_name='google.protobuf.DescriptorProto.ExtensionRange.end', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.DescriptorProto.ExtensionRange.options', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - _DESCRIPTORPROTO_RESERVEDRANGE = _descriptor.Descriptor( - name='ReservedRange', - full_name='google.protobuf.DescriptorProto.ReservedRange', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='start', full_name='google.protobuf.DescriptorProto.ReservedRange.start', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='end', full_name='google.protobuf.DescriptorProto.ReservedRange.end', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - _DESCRIPTORPROTO = _descriptor.Descriptor( - name='DescriptorProto', - full_name='google.protobuf.DescriptorProto', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.DescriptorProto.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='field', full_name='google.protobuf.DescriptorProto.field', index=1, - number=2, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='extension', full_name='google.protobuf.DescriptorProto.extension', index=2, - number=6, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='nested_type', full_name='google.protobuf.DescriptorProto.nested_type', index=3, - number=3, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='enum_type', full_name='google.protobuf.DescriptorProto.enum_type', index=4, - number=4, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='extension_range', full_name='google.protobuf.DescriptorProto.extension_range', index=5, - number=5, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='oneof_decl', full_name='google.protobuf.DescriptorProto.oneof_decl', index=6, - number=8, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.DescriptorProto.options', index=7, - number=7, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='reserved_range', full_name='google.protobuf.DescriptorProto.reserved_range', index=8, - number=9, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='reserved_name', full_name='google.protobuf.DescriptorProto.reserved_name', index=9, - number=10, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[_DESCRIPTORPROTO_EXTENSIONRANGE, _DESCRIPTORPROTO_RESERVEDRANGE, ], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _EXTENSIONRANGEOPTIONS = _descriptor.Descriptor( - name='ExtensionRangeOptions', - full_name='google.protobuf.ExtensionRangeOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.ExtensionRangeOptions.uninterpreted_option', index=0, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _FIELDDESCRIPTORPROTO = _descriptor.Descriptor( - name='FieldDescriptorProto', - full_name='google.protobuf.FieldDescriptorProto', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.FieldDescriptorProto.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='number', full_name='google.protobuf.FieldDescriptorProto.number', index=1, - number=3, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='label', full_name='google.protobuf.FieldDescriptorProto.label', index=2, - number=4, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='type', full_name='google.protobuf.FieldDescriptorProto.type', index=3, - number=5, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='type_name', full_name='google.protobuf.FieldDescriptorProto.type_name', index=4, - number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='extendee', full_name='google.protobuf.FieldDescriptorProto.extendee', index=5, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='default_value', full_name='google.protobuf.FieldDescriptorProto.default_value', index=6, - number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='oneof_index', full_name='google.protobuf.FieldDescriptorProto.oneof_index', index=7, - number=9, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='json_name', full_name='google.protobuf.FieldDescriptorProto.json_name', index=8, - number=10, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.FieldDescriptorProto.options', index=9, - number=8, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='proto3_optional', full_name='google.protobuf.FieldDescriptorProto.proto3_optional', index=10, - number=17, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _FIELDDESCRIPTORPROTO_TYPE, - _FIELDDESCRIPTORPROTO_LABEL, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _ONEOFDESCRIPTORPROTO = _descriptor.Descriptor( - name='OneofDescriptorProto', - full_name='google.protobuf.OneofDescriptorProto', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.OneofDescriptorProto.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.OneofDescriptorProto.options', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE = _descriptor.Descriptor( - name='EnumReservedRange', - full_name='google.protobuf.EnumDescriptorProto.EnumReservedRange', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='start', full_name='google.protobuf.EnumDescriptorProto.EnumReservedRange.start', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='end', full_name='google.protobuf.EnumDescriptorProto.EnumReservedRange.end', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - _ENUMDESCRIPTORPROTO = _descriptor.Descriptor( - name='EnumDescriptorProto', - full_name='google.protobuf.EnumDescriptorProto', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.EnumDescriptorProto.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='value', full_name='google.protobuf.EnumDescriptorProto.value', index=1, - number=2, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.EnumDescriptorProto.options', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='reserved_range', full_name='google.protobuf.EnumDescriptorProto.reserved_range', index=3, - number=4, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='reserved_name', full_name='google.protobuf.EnumDescriptorProto.reserved_name', index=4, - number=5, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[_ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE, ], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _ENUMVALUEDESCRIPTORPROTO = _descriptor.Descriptor( - name='EnumValueDescriptorProto', - full_name='google.protobuf.EnumValueDescriptorProto', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.EnumValueDescriptorProto.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='number', full_name='google.protobuf.EnumValueDescriptorProto.number', index=1, - number=2, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.EnumValueDescriptorProto.options', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _SERVICEDESCRIPTORPROTO = _descriptor.Descriptor( - name='ServiceDescriptorProto', - full_name='google.protobuf.ServiceDescriptorProto', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.ServiceDescriptorProto.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='method', full_name='google.protobuf.ServiceDescriptorProto.method', index=1, - number=2, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.ServiceDescriptorProto.options', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _METHODDESCRIPTORPROTO = _descriptor.Descriptor( - name='MethodDescriptorProto', - full_name='google.protobuf.MethodDescriptorProto', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.MethodDescriptorProto.name', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='input_type', full_name='google.protobuf.MethodDescriptorProto.input_type', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='output_type', full_name='google.protobuf.MethodDescriptorProto.output_type', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='options', full_name='google.protobuf.MethodDescriptorProto.options', index=3, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='client_streaming', full_name='google.protobuf.MethodDescriptorProto.client_streaming', index=4, - number=5, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='server_streaming', full_name='google.protobuf.MethodDescriptorProto.server_streaming', index=5, - number=6, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _FILEOPTIONS = _descriptor.Descriptor( - name='FileOptions', - full_name='google.protobuf.FileOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='java_package', full_name='google.protobuf.FileOptions.java_package', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='java_outer_classname', full_name='google.protobuf.FileOptions.java_outer_classname', index=1, - number=8, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='java_multiple_files', full_name='google.protobuf.FileOptions.java_multiple_files', index=2, - number=10, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='java_generate_equals_and_hash', full_name='google.protobuf.FileOptions.java_generate_equals_and_hash', index=3, - number=20, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='java_string_check_utf8', full_name='google.protobuf.FileOptions.java_string_check_utf8', index=4, - number=27, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='optimize_for', full_name='google.protobuf.FileOptions.optimize_for', index=5, - number=9, type=14, cpp_type=8, label=1, - has_default_value=True, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='go_package', full_name='google.protobuf.FileOptions.go_package', index=6, - number=11, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='cc_generic_services', full_name='google.protobuf.FileOptions.cc_generic_services', index=7, - number=16, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='java_generic_services', full_name='google.protobuf.FileOptions.java_generic_services', index=8, - number=17, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='py_generic_services', full_name='google.protobuf.FileOptions.py_generic_services', index=9, - number=18, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='php_generic_services', full_name='google.protobuf.FileOptions.php_generic_services', index=10, - number=42, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='deprecated', full_name='google.protobuf.FileOptions.deprecated', index=11, - number=23, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='cc_enable_arenas', full_name='google.protobuf.FileOptions.cc_enable_arenas', index=12, - number=31, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=True, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='objc_class_prefix', full_name='google.protobuf.FileOptions.objc_class_prefix', index=13, - number=36, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='csharp_namespace', full_name='google.protobuf.FileOptions.csharp_namespace', index=14, - number=37, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='swift_prefix', full_name='google.protobuf.FileOptions.swift_prefix', index=15, - number=39, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='php_class_prefix', full_name='google.protobuf.FileOptions.php_class_prefix', index=16, - number=40, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='php_namespace', full_name='google.protobuf.FileOptions.php_namespace', index=17, - number=41, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='php_metadata_namespace', full_name='google.protobuf.FileOptions.php_metadata_namespace', index=18, - number=44, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='ruby_package', full_name='google.protobuf.FileOptions.ruby_package', index=19, - number=45, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.FileOptions.uninterpreted_option', index=20, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _FILEOPTIONS_OPTIMIZEMODE, - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _MESSAGEOPTIONS = _descriptor.Descriptor( - name='MessageOptions', - full_name='google.protobuf.MessageOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='message_set_wire_format', full_name='google.protobuf.MessageOptions.message_set_wire_format', index=0, - number=1, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='no_standard_descriptor_accessor', full_name='google.protobuf.MessageOptions.no_standard_descriptor_accessor', index=1, - number=2, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='deprecated', full_name='google.protobuf.MessageOptions.deprecated', index=2, - number=3, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='map_entry', full_name='google.protobuf.MessageOptions.map_entry', index=3, - number=7, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.MessageOptions.uninterpreted_option', index=4, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _FIELDOPTIONS = _descriptor.Descriptor( - name='FieldOptions', - full_name='google.protobuf.FieldOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='ctype', full_name='google.protobuf.FieldOptions.ctype', index=0, - number=1, type=14, cpp_type=8, label=1, - has_default_value=True, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='packed', full_name='google.protobuf.FieldOptions.packed', index=1, - number=2, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='jstype', full_name='google.protobuf.FieldOptions.jstype', index=2, - number=6, type=14, cpp_type=8, label=1, - has_default_value=True, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='lazy', full_name='google.protobuf.FieldOptions.lazy', index=3, - number=5, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='unverified_lazy', full_name='google.protobuf.FieldOptions.unverified_lazy', index=4, - number=15, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='deprecated', full_name='google.protobuf.FieldOptions.deprecated', index=5, - number=3, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='weak', full_name='google.protobuf.FieldOptions.weak', index=6, - number=10, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.FieldOptions.uninterpreted_option', index=7, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _FIELDOPTIONS_CTYPE, - _FIELDOPTIONS_JSTYPE, - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _ONEOFOPTIONS = _descriptor.Descriptor( - name='OneofOptions', - full_name='google.protobuf.OneofOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.OneofOptions.uninterpreted_option', index=0, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _ENUMOPTIONS = _descriptor.Descriptor( - name='EnumOptions', - full_name='google.protobuf.EnumOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='allow_alias', full_name='google.protobuf.EnumOptions.allow_alias', index=0, - number=2, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='deprecated', full_name='google.protobuf.EnumOptions.deprecated', index=1, - number=3, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.EnumOptions.uninterpreted_option', index=2, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _ENUMVALUEOPTIONS = _descriptor.Descriptor( - name='EnumValueOptions', - full_name='google.protobuf.EnumValueOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='deprecated', full_name='google.protobuf.EnumValueOptions.deprecated', index=0, - number=1, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.EnumValueOptions.uninterpreted_option', index=1, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _SERVICEOPTIONS = _descriptor.Descriptor( - name='ServiceOptions', - full_name='google.protobuf.ServiceOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='deprecated', full_name='google.protobuf.ServiceOptions.deprecated', index=0, - number=33, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.ServiceOptions.uninterpreted_option', index=1, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _METHODOPTIONS = _descriptor.Descriptor( - name='MethodOptions', - full_name='google.protobuf.MethodOptions', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='deprecated', full_name='google.protobuf.MethodOptions.deprecated', index=0, - number=33, type=8, cpp_type=7, label=1, - has_default_value=True, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='idempotency_level', full_name='google.protobuf.MethodOptions.idempotency_level', index=1, - number=34, type=14, cpp_type=8, label=1, - has_default_value=True, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='uninterpreted_option', full_name='google.protobuf.MethodOptions.uninterpreted_option', index=2, - number=999, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _METHODOPTIONS_IDEMPOTENCYLEVEL, - ], - serialized_options=None, - is_extendable=True, - syntax='proto2', - extension_ranges=[(1000, 536870912), ], - oneofs=[ - ], - ) - - - _UNINTERPRETEDOPTION_NAMEPART = _descriptor.Descriptor( - name='NamePart', - full_name='google.protobuf.UninterpretedOption.NamePart', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name_part', full_name='google.protobuf.UninterpretedOption.NamePart.name_part', index=0, - number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='is_extension', full_name='google.protobuf.UninterpretedOption.NamePart.is_extension', index=1, - number=2, type=8, cpp_type=7, label=2, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - _UNINTERPRETEDOPTION = _descriptor.Descriptor( - name='UninterpretedOption', - full_name='google.protobuf.UninterpretedOption', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='name', full_name='google.protobuf.UninterpretedOption.name', index=0, - number=2, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='identifier_value', full_name='google.protobuf.UninterpretedOption.identifier_value', index=1, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='positive_int_value', full_name='google.protobuf.UninterpretedOption.positive_int_value', index=2, - number=4, type=4, cpp_type=4, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='negative_int_value', full_name='google.protobuf.UninterpretedOption.negative_int_value', index=3, - number=5, type=3, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='double_value', full_name='google.protobuf.UninterpretedOption.double_value', index=4, - number=6, type=1, cpp_type=5, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='string_value', full_name='google.protobuf.UninterpretedOption.string_value', index=5, - number=7, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=b"", - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='aggregate_value', full_name='google.protobuf.UninterpretedOption.aggregate_value', index=6, - number=8, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[_UNINTERPRETEDOPTION_NAMEPART, ], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _SOURCECODEINFO_LOCATION = _descriptor.Descriptor( - name='Location', - full_name='google.protobuf.SourceCodeInfo.Location', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='path', full_name='google.protobuf.SourceCodeInfo.Location.path', index=0, - number=1, type=5, cpp_type=1, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='span', full_name='google.protobuf.SourceCodeInfo.Location.span', index=1, - number=2, type=5, cpp_type=1, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='leading_comments', full_name='google.protobuf.SourceCodeInfo.Location.leading_comments', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='trailing_comments', full_name='google.protobuf.SourceCodeInfo.Location.trailing_comments', index=3, - number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='leading_detached_comments', full_name='google.protobuf.SourceCodeInfo.Location.leading_detached_comments', index=4, - number=6, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - _SOURCECODEINFO = _descriptor.Descriptor( - name='SourceCodeInfo', - full_name='google.protobuf.SourceCodeInfo', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='location', full_name='google.protobuf.SourceCodeInfo.location', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[_SOURCECODEINFO_LOCATION, ], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - - _GENERATEDCODEINFO_ANNOTATION = _descriptor.Descriptor( - name='Annotation', - full_name='google.protobuf.GeneratedCodeInfo.Annotation', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='path', full_name='google.protobuf.GeneratedCodeInfo.Annotation.path', index=0, - number=1, type=5, cpp_type=1, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='source_file', full_name='google.protobuf.GeneratedCodeInfo.Annotation.source_file', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='begin', full_name='google.protobuf.GeneratedCodeInfo.Annotation.begin', index=2, - number=3, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='end', full_name='google.protobuf.GeneratedCodeInfo.Annotation.end', index=3, - number=4, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - _GENERATEDCODEINFO = _descriptor.Descriptor( - name='GeneratedCodeInfo', - full_name='google.protobuf.GeneratedCodeInfo', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='annotation', full_name='google.protobuf.GeneratedCodeInfo.annotation', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[_GENERATEDCODEINFO_ANNOTATION, ], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - ) - - _FILEDESCRIPTORSET.fields_by_name['file'].message_type = _FILEDESCRIPTORPROTO - _FILEDESCRIPTORPROTO.fields_by_name['message_type'].message_type = _DESCRIPTORPROTO - _FILEDESCRIPTORPROTO.fields_by_name['enum_type'].message_type = _ENUMDESCRIPTORPROTO - _FILEDESCRIPTORPROTO.fields_by_name['service'].message_type = _SERVICEDESCRIPTORPROTO - _FILEDESCRIPTORPROTO.fields_by_name['extension'].message_type = _FIELDDESCRIPTORPROTO - _FILEDESCRIPTORPROTO.fields_by_name['options'].message_type = _FILEOPTIONS - _FILEDESCRIPTORPROTO.fields_by_name['source_code_info'].message_type = _SOURCECODEINFO - _DESCRIPTORPROTO_EXTENSIONRANGE.fields_by_name['options'].message_type = _EXTENSIONRANGEOPTIONS - _DESCRIPTORPROTO_EXTENSIONRANGE.containing_type = _DESCRIPTORPROTO - _DESCRIPTORPROTO_RESERVEDRANGE.containing_type = _DESCRIPTORPROTO - _DESCRIPTORPROTO.fields_by_name['field'].message_type = _FIELDDESCRIPTORPROTO - _DESCRIPTORPROTO.fields_by_name['extension'].message_type = _FIELDDESCRIPTORPROTO - _DESCRIPTORPROTO.fields_by_name['nested_type'].message_type = _DESCRIPTORPROTO - _DESCRIPTORPROTO.fields_by_name['enum_type'].message_type = _ENUMDESCRIPTORPROTO - _DESCRIPTORPROTO.fields_by_name['extension_range'].message_type = _DESCRIPTORPROTO_EXTENSIONRANGE - _DESCRIPTORPROTO.fields_by_name['oneof_decl'].message_type = _ONEOFDESCRIPTORPROTO - _DESCRIPTORPROTO.fields_by_name['options'].message_type = _MESSAGEOPTIONS - _DESCRIPTORPROTO.fields_by_name['reserved_range'].message_type = _DESCRIPTORPROTO_RESERVEDRANGE - _EXTENSIONRANGEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _FIELDDESCRIPTORPROTO.fields_by_name['label'].enum_type = _FIELDDESCRIPTORPROTO_LABEL - _FIELDDESCRIPTORPROTO.fields_by_name['type'].enum_type = _FIELDDESCRIPTORPROTO_TYPE - _FIELDDESCRIPTORPROTO.fields_by_name['options'].message_type = _FIELDOPTIONS - _FIELDDESCRIPTORPROTO_TYPE.containing_type = _FIELDDESCRIPTORPROTO - _FIELDDESCRIPTORPROTO_LABEL.containing_type = _FIELDDESCRIPTORPROTO - _ONEOFDESCRIPTORPROTO.fields_by_name['options'].message_type = _ONEOFOPTIONS - _ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE.containing_type = _ENUMDESCRIPTORPROTO - _ENUMDESCRIPTORPROTO.fields_by_name['value'].message_type = _ENUMVALUEDESCRIPTORPROTO - _ENUMDESCRIPTORPROTO.fields_by_name['options'].message_type = _ENUMOPTIONS - _ENUMDESCRIPTORPROTO.fields_by_name['reserved_range'].message_type = _ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE - _ENUMVALUEDESCRIPTORPROTO.fields_by_name['options'].message_type = _ENUMVALUEOPTIONS - _SERVICEDESCRIPTORPROTO.fields_by_name['method'].message_type = _METHODDESCRIPTORPROTO - _SERVICEDESCRIPTORPROTO.fields_by_name['options'].message_type = _SERVICEOPTIONS - _METHODDESCRIPTORPROTO.fields_by_name['options'].message_type = _METHODOPTIONS - _FILEOPTIONS.fields_by_name['optimize_for'].enum_type = _FILEOPTIONS_OPTIMIZEMODE - _FILEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _FILEOPTIONS_OPTIMIZEMODE.containing_type = _FILEOPTIONS - _MESSAGEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _FIELDOPTIONS.fields_by_name['ctype'].enum_type = _FIELDOPTIONS_CTYPE - _FIELDOPTIONS.fields_by_name['jstype'].enum_type = _FIELDOPTIONS_JSTYPE - _FIELDOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _FIELDOPTIONS_CTYPE.containing_type = _FIELDOPTIONS - _FIELDOPTIONS_JSTYPE.containing_type = _FIELDOPTIONS - _ONEOFOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _ENUMOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _ENUMVALUEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _SERVICEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _METHODOPTIONS.fields_by_name['idempotency_level'].enum_type = _METHODOPTIONS_IDEMPOTENCYLEVEL - _METHODOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION - _METHODOPTIONS_IDEMPOTENCYLEVEL.containing_type = _METHODOPTIONS - _UNINTERPRETEDOPTION_NAMEPART.containing_type = _UNINTERPRETEDOPTION - _UNINTERPRETEDOPTION.fields_by_name['name'].message_type = _UNINTERPRETEDOPTION_NAMEPART - _SOURCECODEINFO_LOCATION.containing_type = _SOURCECODEINFO - _SOURCECODEINFO.fields_by_name['location'].message_type = _SOURCECODEINFO_LOCATION - _GENERATEDCODEINFO_ANNOTATION.containing_type = _GENERATEDCODEINFO - _GENERATEDCODEINFO.fields_by_name['annotation'].message_type = _GENERATEDCODEINFO_ANNOTATION - DESCRIPTOR.message_types_by_name['FileDescriptorSet'] = _FILEDESCRIPTORSET - DESCRIPTOR.message_types_by_name['FileDescriptorProto'] = _FILEDESCRIPTORPROTO - DESCRIPTOR.message_types_by_name['DescriptorProto'] = _DESCRIPTORPROTO - DESCRIPTOR.message_types_by_name['ExtensionRangeOptions'] = _EXTENSIONRANGEOPTIONS - DESCRIPTOR.message_types_by_name['FieldDescriptorProto'] = _FIELDDESCRIPTORPROTO - DESCRIPTOR.message_types_by_name['OneofDescriptorProto'] = _ONEOFDESCRIPTORPROTO - DESCRIPTOR.message_types_by_name['EnumDescriptorProto'] = _ENUMDESCRIPTORPROTO - DESCRIPTOR.message_types_by_name['EnumValueDescriptorProto'] = _ENUMVALUEDESCRIPTORPROTO - DESCRIPTOR.message_types_by_name['ServiceDescriptorProto'] = _SERVICEDESCRIPTORPROTO - DESCRIPTOR.message_types_by_name['MethodDescriptorProto'] = _METHODDESCRIPTORPROTO - DESCRIPTOR.message_types_by_name['FileOptions'] = _FILEOPTIONS - DESCRIPTOR.message_types_by_name['MessageOptions'] = _MESSAGEOPTIONS - DESCRIPTOR.message_types_by_name['FieldOptions'] = _FIELDOPTIONS - DESCRIPTOR.message_types_by_name['OneofOptions'] = _ONEOFOPTIONS - DESCRIPTOR.message_types_by_name['EnumOptions'] = _ENUMOPTIONS - DESCRIPTOR.message_types_by_name['EnumValueOptions'] = _ENUMVALUEOPTIONS - DESCRIPTOR.message_types_by_name['ServiceOptions'] = _SERVICEOPTIONS - DESCRIPTOR.message_types_by_name['MethodOptions'] = _METHODOPTIONS - DESCRIPTOR.message_types_by_name['UninterpretedOption'] = _UNINTERPRETEDOPTION - DESCRIPTOR.message_types_by_name['SourceCodeInfo'] = _SOURCECODEINFO - DESCRIPTOR.message_types_by_name['GeneratedCodeInfo'] = _GENERATEDCODEINFO - _sym_db.RegisterFileDescriptor(DESCRIPTOR) - -else: - _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.descriptor_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _FILEDESCRIPTORSET._serialized_start=53 - _FILEDESCRIPTORSET._serialized_end=124 - _FILEDESCRIPTORPROTO._serialized_start=127 - _FILEDESCRIPTORPROTO._serialized_end=602 - _DESCRIPTORPROTO._serialized_start=605 - _DESCRIPTORPROTO._serialized_end=1286 - _DESCRIPTORPROTO_EXTENSIONRANGE._serialized_start=1140 - _DESCRIPTORPROTO_EXTENSIONRANGE._serialized_end=1241 - _DESCRIPTORPROTO_RESERVEDRANGE._serialized_start=1243 - _DESCRIPTORPROTO_RESERVEDRANGE._serialized_end=1286 - _EXTENSIONRANGEOPTIONS._serialized_start=1288 - _EXTENSIONRANGEOPTIONS._serialized_end=1391 - _FIELDDESCRIPTORPROTO._serialized_start=1394 - _FIELDDESCRIPTORPROTO._serialized_end=2119 - _FIELDDESCRIPTORPROTO_TYPE._serialized_start=1740 - _FIELDDESCRIPTORPROTO_TYPE._serialized_end=2050 - _FIELDDESCRIPTORPROTO_LABEL._serialized_start=2052 - _FIELDDESCRIPTORPROTO_LABEL._serialized_end=2119 - _ONEOFDESCRIPTORPROTO._serialized_start=2121 - _ONEOFDESCRIPTORPROTO._serialized_end=2205 - _ENUMDESCRIPTORPROTO._serialized_start=2208 - _ENUMDESCRIPTORPROTO._serialized_end=2500 - _ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE._serialized_start=2453 - _ENUMDESCRIPTORPROTO_ENUMRESERVEDRANGE._serialized_end=2500 - _ENUMVALUEDESCRIPTORPROTO._serialized_start=2502 - _ENUMVALUEDESCRIPTORPROTO._serialized_end=2610 - _SERVICEDESCRIPTORPROTO._serialized_start=2613 - _SERVICEDESCRIPTORPROTO._serialized_end=2757 - _METHODDESCRIPTORPROTO._serialized_start=2760 - _METHODDESCRIPTORPROTO._serialized_end=2953 - _FILEOPTIONS._serialized_start=2956 - _FILEOPTIONS._serialized_end=3761 - _FILEOPTIONS_OPTIMIZEMODE._serialized_start=3686 - _FILEOPTIONS_OPTIMIZEMODE._serialized_end=3744 - _MESSAGEOPTIONS._serialized_start=3764 - _MESSAGEOPTIONS._serialized_end=4024 - _FIELDOPTIONS._serialized_start=4027 - _FIELDOPTIONS._serialized_end=4473 - _FIELDOPTIONS_CTYPE._serialized_start=4354 - _FIELDOPTIONS_CTYPE._serialized_end=4401 - _FIELDOPTIONS_JSTYPE._serialized_start=4403 - _FIELDOPTIONS_JSTYPE._serialized_end=4456 - _ONEOFOPTIONS._serialized_start=4475 - _ONEOFOPTIONS._serialized_end=4569 - _ENUMOPTIONS._serialized_start=4572 - _ENUMOPTIONS._serialized_end=4719 - _ENUMVALUEOPTIONS._serialized_start=4721 - _ENUMVALUEOPTIONS._serialized_end=4846 - _SERVICEOPTIONS._serialized_start=4848 - _SERVICEOPTIONS._serialized_end=4971 - _METHODOPTIONS._serialized_start=4974 - _METHODOPTIONS._serialized_end=5275 - _METHODOPTIONS_IDEMPOTENCYLEVEL._serialized_start=5184 - _METHODOPTIONS_IDEMPOTENCYLEVEL._serialized_end=5264 - _UNINTERPRETEDOPTION._serialized_start=5278 - _UNINTERPRETEDOPTION._serialized_end=5564 - _UNINTERPRETEDOPTION_NAMEPART._serialized_start=5513 - _UNINTERPRETEDOPTION_NAMEPART._serialized_end=5564 - _SOURCECODEINFO._serialized_start=5567 - _SOURCECODEINFO._serialized_end=5780 - _SOURCECODEINFO_LOCATION._serialized_start=5646 - _SOURCECODEINFO_LOCATION._serialized_end=5780 - _GENERATEDCODEINFO._serialized_start=5783 - _GENERATEDCODEINFO._serialized_end=5950 - _GENERATEDCODEINFO_ANNOTATION._serialized_start=5871 - _GENERATEDCODEINFO_ANNOTATION._serialized_end=5950 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/descriptor_pool.py b/scripts/protobuf3/protobuf3/descriptor_pool.py deleted file mode 100644 index 911372a..0000000 --- a/scripts/protobuf3/protobuf3/descriptor_pool.py +++ /dev/null @@ -1,1295 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Provides DescriptorPool to use as a container for proto2 descriptors. - -The DescriptorPool is used in conjection with a DescriptorDatabase to maintain -a collection of protocol buffer descriptors for use when dynamically creating -message types at runtime. - -For most applications protocol buffers should be used via modules generated by -the protocol buffer compiler tool. This should only be used when the type of -protocol buffers used in an application or library cannot be predetermined. - -Below is a straightforward example on how to use this class:: - - pool = DescriptorPool() - file_descriptor_protos = [ ... ] - for file_descriptor_proto in file_descriptor_protos: - pool.Add(file_descriptor_proto) - my_message_descriptor = pool.FindMessageTypeByName('some.package.MessageType') - -The message descriptor can be used in conjunction with the message_factory -module in order to create a protocol buffer class that can be encoded and -decoded. - -If you want to get a Python class for the specified proto, use the -helper functions inside google.protobuf.message_factory -directly instead of this class. -""" - -__author__ = 'matthewtoia@google.com (Matt Toia)' - -import collections -import warnings - -from google.protobuf import descriptor -from google.protobuf import descriptor_database -from google.protobuf import text_encoding - - -_USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS # pylint: disable=protected-access - - -def _Deprecated(func): - """Mark functions as deprecated.""" - - def NewFunc(*args, **kwargs): - warnings.warn( - 'Call to deprecated function %s(). Note: Do add unlinked descriptors ' - 'to descriptor_pool is wrong. Use Add() or AddSerializedFile() ' - 'instead.' % func.__name__, - category=DeprecationWarning) - return func(*args, **kwargs) - NewFunc.__name__ = func.__name__ - NewFunc.__doc__ = func.__doc__ - NewFunc.__dict__.update(func.__dict__) - return NewFunc - - -def _NormalizeFullyQualifiedName(name): - """Remove leading period from fully-qualified type name. - - Due to b/13860351 in descriptor_database.py, types in the root namespace are - generated with a leading period. This function removes that prefix. - - Args: - name (str): The fully-qualified symbol name. - - Returns: - str: The normalized fully-qualified symbol name. - """ - return name.lstrip('.') - - -def _OptionsOrNone(descriptor_proto): - """Returns the value of the field `options`, or None if it is not set.""" - if descriptor_proto.HasField('options'): - return descriptor_proto.options - else: - return None - - -def _IsMessageSetExtension(field): - return (field.is_extension and - field.containing_type.has_options and - field.containing_type.GetOptions().message_set_wire_format and - field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and - field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL) - - -class DescriptorPool(object): - """A collection of protobufs dynamically constructed by descriptor protos.""" - - if _USE_C_DESCRIPTORS: - - def __new__(cls, descriptor_db=None): - # pylint: disable=protected-access - return descriptor._message.DescriptorPool(descriptor_db) - - def __init__(self, descriptor_db=None): - """Initializes a Pool of proto buffs. - - The descriptor_db argument to the constructor is provided to allow - specialized file descriptor proto lookup code to be triggered on demand. An - example would be an implementation which will read and compile a file - specified in a call to FindFileByName() and not require the call to Add() - at all. Results from this database will be cached internally here as well. - - Args: - descriptor_db: A secondary source of file descriptors. - """ - - self._internal_db = descriptor_database.DescriptorDatabase() - self._descriptor_db = descriptor_db - self._descriptors = {} - self._enum_descriptors = {} - self._service_descriptors = {} - self._file_descriptors = {} - self._toplevel_extensions = {} - # TODO(jieluo): Remove _file_desc_by_toplevel_extension after - # maybe year 2020 for compatibility issue (with 3.4.1 only). - self._file_desc_by_toplevel_extension = {} - self._top_enum_values = {} - # We store extensions in two two-level mappings: The first key is the - # descriptor of the message being extended, the second key is the extension - # full name or its tag number. - self._extensions_by_name = collections.defaultdict(dict) - self._extensions_by_number = collections.defaultdict(dict) - - def _CheckConflictRegister(self, desc, desc_name, file_name): - """Check if the descriptor name conflicts with another of the same name. - - Args: - desc: Descriptor of a message, enum, service, extension or enum value. - desc_name (str): the full name of desc. - file_name (str): The file name of descriptor. - """ - for register, descriptor_type in [ - (self._descriptors, descriptor.Descriptor), - (self._enum_descriptors, descriptor.EnumDescriptor), - (self._service_descriptors, descriptor.ServiceDescriptor), - (self._toplevel_extensions, descriptor.FieldDescriptor), - (self._top_enum_values, descriptor.EnumValueDescriptor)]: - if desc_name in register: - old_desc = register[desc_name] - if isinstance(old_desc, descriptor.EnumValueDescriptor): - old_file = old_desc.type.file.name - else: - old_file = old_desc.file.name - - if not isinstance(desc, descriptor_type) or ( - old_file != file_name): - error_msg = ('Conflict register for file "' + file_name + - '": ' + desc_name + - ' is already defined in file "' + - old_file + '". Please fix the conflict by adding ' - 'package name on the proto file, or use different ' - 'name for the duplication.') - if isinstance(desc, descriptor.EnumValueDescriptor): - error_msg += ('\nNote: enum values appear as ' - 'siblings of the enum type instead of ' - 'children of it.') - - raise TypeError(error_msg) - - return - - def Add(self, file_desc_proto): - """Adds the FileDescriptorProto and its types to this pool. - - Args: - file_desc_proto (FileDescriptorProto): The file descriptor to add. - """ - - self._internal_db.Add(file_desc_proto) - - def AddSerializedFile(self, serialized_file_desc_proto): - """Adds the FileDescriptorProto and its types to this pool. - - Args: - serialized_file_desc_proto (bytes): A bytes string, serialization of the - :class:`FileDescriptorProto` to add. - - Returns: - FileDescriptor: Descriptor for the added file. - """ - - # pylint: disable=g-import-not-at-top - from google.protobuf import descriptor_pb2 - file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString( - serialized_file_desc_proto) - file_desc = self._ConvertFileProtoToFileDescriptor(file_desc_proto) - file_desc.serialized_pb = serialized_file_desc_proto - return file_desc - - # Add Descriptor to descriptor pool is dreprecated. Please use Add() - # or AddSerializedFile() to add a FileDescriptorProto instead. - @_Deprecated - def AddDescriptor(self, desc): - self._AddDescriptor(desc) - - # Never call this method. It is for internal usage only. - def _AddDescriptor(self, desc): - """Adds a Descriptor to the pool, non-recursively. - - If the Descriptor contains nested messages or enums, the caller must - explicitly register them. This method also registers the FileDescriptor - associated with the message. - - Args: - desc: A Descriptor. - """ - if not isinstance(desc, descriptor.Descriptor): - raise TypeError('Expected instance of descriptor.Descriptor.') - - self._CheckConflictRegister(desc, desc.full_name, desc.file.name) - - self._descriptors[desc.full_name] = desc - self._AddFileDescriptor(desc.file) - - # Add EnumDescriptor to descriptor pool is dreprecated. Please use Add() - # or AddSerializedFile() to add a FileDescriptorProto instead. - @_Deprecated - def AddEnumDescriptor(self, enum_desc): - self._AddEnumDescriptor(enum_desc) - - # Never call this method. It is for internal usage only. - def _AddEnumDescriptor(self, enum_desc): - """Adds an EnumDescriptor to the pool. - - This method also registers the FileDescriptor associated with the enum. - - Args: - enum_desc: An EnumDescriptor. - """ - - if not isinstance(enum_desc, descriptor.EnumDescriptor): - raise TypeError('Expected instance of descriptor.EnumDescriptor.') - - file_name = enum_desc.file.name - self._CheckConflictRegister(enum_desc, enum_desc.full_name, file_name) - self._enum_descriptors[enum_desc.full_name] = enum_desc - - # Top enum values need to be indexed. - # Count the number of dots to see whether the enum is toplevel or nested - # in a message. We cannot use enum_desc.containing_type at this stage. - if enum_desc.file.package: - top_level = (enum_desc.full_name.count('.') - - enum_desc.file.package.count('.') == 1) - else: - top_level = enum_desc.full_name.count('.') == 0 - if top_level: - file_name = enum_desc.file.name - package = enum_desc.file.package - for enum_value in enum_desc.values: - full_name = _NormalizeFullyQualifiedName( - '.'.join((package, enum_value.name))) - self._CheckConflictRegister(enum_value, full_name, file_name) - self._top_enum_values[full_name] = enum_value - self._AddFileDescriptor(enum_desc.file) - - # Add ServiceDescriptor to descriptor pool is dreprecated. Please use Add() - # or AddSerializedFile() to add a FileDescriptorProto instead. - @_Deprecated - def AddServiceDescriptor(self, service_desc): - self._AddServiceDescriptor(service_desc) - - # Never call this method. It is for internal usage only. - def _AddServiceDescriptor(self, service_desc): - """Adds a ServiceDescriptor to the pool. - - Args: - service_desc: A ServiceDescriptor. - """ - - if not isinstance(service_desc, descriptor.ServiceDescriptor): - raise TypeError('Expected instance of descriptor.ServiceDescriptor.') - - self._CheckConflictRegister(service_desc, service_desc.full_name, - service_desc.file.name) - self._service_descriptors[service_desc.full_name] = service_desc - - # Add ExtensionDescriptor to descriptor pool is dreprecated. Please use Add() - # or AddSerializedFile() to add a FileDescriptorProto instead. - @_Deprecated - def AddExtensionDescriptor(self, extension): - self._AddExtensionDescriptor(extension) - - # Never call this method. It is for internal usage only. - def _AddExtensionDescriptor(self, extension): - """Adds a FieldDescriptor describing an extension to the pool. - - Args: - extension: A FieldDescriptor. - - Raises: - AssertionError: when another extension with the same number extends the - same message. - TypeError: when the specified extension is not a - descriptor.FieldDescriptor. - """ - if not (isinstance(extension, descriptor.FieldDescriptor) and - extension.is_extension): - raise TypeError('Expected an extension descriptor.') - - if extension.extension_scope is None: - self._toplevel_extensions[extension.full_name] = extension - - try: - existing_desc = self._extensions_by_number[ - extension.containing_type][extension.number] - except KeyError: - pass - else: - if extension is not existing_desc: - raise AssertionError( - 'Extensions "%s" and "%s" both try to extend message type "%s" ' - 'with field number %d.' % - (extension.full_name, existing_desc.full_name, - extension.containing_type.full_name, extension.number)) - - self._extensions_by_number[extension.containing_type][ - extension.number] = extension - self._extensions_by_name[extension.containing_type][ - extension.full_name] = extension - - # Also register MessageSet extensions with the type name. - if _IsMessageSetExtension(extension): - self._extensions_by_name[extension.containing_type][ - extension.message_type.full_name] = extension - - @_Deprecated - def AddFileDescriptor(self, file_desc): - self._InternalAddFileDescriptor(file_desc) - - # Never call this method. It is for internal usage only. - def _InternalAddFileDescriptor(self, file_desc): - """Adds a FileDescriptor to the pool, non-recursively. - - If the FileDescriptor contains messages or enums, the caller must explicitly - register them. - - Args: - file_desc: A FileDescriptor. - """ - - self._AddFileDescriptor(file_desc) - # TODO(jieluo): This is a temporary solution for FieldDescriptor.file. - # FieldDescriptor.file is added in code gen. Remove this solution after - # maybe 2020 for compatibility reason (with 3.4.1 only). - for extension in file_desc.extensions_by_name.values(): - self._file_desc_by_toplevel_extension[ - extension.full_name] = file_desc - - def _AddFileDescriptor(self, file_desc): - """Adds a FileDescriptor to the pool, non-recursively. - - If the FileDescriptor contains messages or enums, the caller must explicitly - register them. - - Args: - file_desc: A FileDescriptor. - """ - - if not isinstance(file_desc, descriptor.FileDescriptor): - raise TypeError('Expected instance of descriptor.FileDescriptor.') - self._file_descriptors[file_desc.name] = file_desc - - def FindFileByName(self, file_name): - """Gets a FileDescriptor by file name. - - Args: - file_name (str): The path to the file to get a descriptor for. - - Returns: - FileDescriptor: The descriptor for the named file. - - Raises: - KeyError: if the file cannot be found in the pool. - """ - - try: - return self._file_descriptors[file_name] - except KeyError: - pass - - try: - file_proto = self._internal_db.FindFileByName(file_name) - except KeyError as error: - if self._descriptor_db: - file_proto = self._descriptor_db.FindFileByName(file_name) - else: - raise error - if not file_proto: - raise KeyError('Cannot find a file named %s' % file_name) - return self._ConvertFileProtoToFileDescriptor(file_proto) - - def FindFileContainingSymbol(self, symbol): - """Gets the FileDescriptor for the file containing the specified symbol. - - Args: - symbol (str): The name of the symbol to search for. - - Returns: - FileDescriptor: Descriptor for the file that contains the specified - symbol. - - Raises: - KeyError: if the file cannot be found in the pool. - """ - - symbol = _NormalizeFullyQualifiedName(symbol) - try: - return self._InternalFindFileContainingSymbol(symbol) - except KeyError: - pass - - try: - # Try fallback database. Build and find again if possible. - self._FindFileContainingSymbolInDb(symbol) - return self._InternalFindFileContainingSymbol(symbol) - except KeyError: - raise KeyError('Cannot find a file containing %s' % symbol) - - def _InternalFindFileContainingSymbol(self, symbol): - """Gets the already built FileDescriptor containing the specified symbol. - - Args: - symbol (str): The name of the symbol to search for. - - Returns: - FileDescriptor: Descriptor for the file that contains the specified - symbol. - - Raises: - KeyError: if the file cannot be found in the pool. - """ - try: - return self._descriptors[symbol].file - except KeyError: - pass - - try: - return self._enum_descriptors[symbol].file - except KeyError: - pass - - try: - return self._service_descriptors[symbol].file - except KeyError: - pass - - try: - return self._top_enum_values[symbol].type.file - except KeyError: - pass - - try: - return self._file_desc_by_toplevel_extension[symbol] - except KeyError: - pass - - # Try fields, enum values and nested extensions inside a message. - top_name, _, sub_name = symbol.rpartition('.') - try: - message = self.FindMessageTypeByName(top_name) - assert (sub_name in message.extensions_by_name or - sub_name in message.fields_by_name or - sub_name in message.enum_values_by_name) - return message.file - except (KeyError, AssertionError): - raise KeyError('Cannot find a file containing %s' % symbol) - - def FindMessageTypeByName(self, full_name): - """Loads the named descriptor from the pool. - - Args: - full_name (str): The full name of the descriptor to load. - - Returns: - Descriptor: The descriptor for the named type. - - Raises: - KeyError: if the message cannot be found in the pool. - """ - - full_name = _NormalizeFullyQualifiedName(full_name) - if full_name not in self._descriptors: - self._FindFileContainingSymbolInDb(full_name) - return self._descriptors[full_name] - - def FindEnumTypeByName(self, full_name): - """Loads the named enum descriptor from the pool. - - Args: - full_name (str): The full name of the enum descriptor to load. - - Returns: - EnumDescriptor: The enum descriptor for the named type. - - Raises: - KeyError: if the enum cannot be found in the pool. - """ - - full_name = _NormalizeFullyQualifiedName(full_name) - if full_name not in self._enum_descriptors: - self._FindFileContainingSymbolInDb(full_name) - return self._enum_descriptors[full_name] - - def FindFieldByName(self, full_name): - """Loads the named field descriptor from the pool. - - Args: - full_name (str): The full name of the field descriptor to load. - - Returns: - FieldDescriptor: The field descriptor for the named field. - - Raises: - KeyError: if the field cannot be found in the pool. - """ - full_name = _NormalizeFullyQualifiedName(full_name) - message_name, _, field_name = full_name.rpartition('.') - message_descriptor = self.FindMessageTypeByName(message_name) - return message_descriptor.fields_by_name[field_name] - - def FindOneofByName(self, full_name): - """Loads the named oneof descriptor from the pool. - - Args: - full_name (str): The full name of the oneof descriptor to load. - - Returns: - OneofDescriptor: The oneof descriptor for the named oneof. - - Raises: - KeyError: if the oneof cannot be found in the pool. - """ - full_name = _NormalizeFullyQualifiedName(full_name) - message_name, _, oneof_name = full_name.rpartition('.') - message_descriptor = self.FindMessageTypeByName(message_name) - return message_descriptor.oneofs_by_name[oneof_name] - - def FindExtensionByName(self, full_name): - """Loads the named extension descriptor from the pool. - - Args: - full_name (str): The full name of the extension descriptor to load. - - Returns: - FieldDescriptor: The field descriptor for the named extension. - - Raises: - KeyError: if the extension cannot be found in the pool. - """ - full_name = _NormalizeFullyQualifiedName(full_name) - try: - # The proto compiler does not give any link between the FileDescriptor - # and top-level extensions unless the FileDescriptorProto is added to - # the DescriptorDatabase, but this can impact memory usage. - # So we registered these extensions by name explicitly. - return self._toplevel_extensions[full_name] - except KeyError: - pass - message_name, _, extension_name = full_name.rpartition('.') - try: - # Most extensions are nested inside a message. - scope = self.FindMessageTypeByName(message_name) - except KeyError: - # Some extensions are defined at file scope. - scope = self._FindFileContainingSymbolInDb(full_name) - return scope.extensions_by_name[extension_name] - - def FindExtensionByNumber(self, message_descriptor, number): - """Gets the extension of the specified message with the specified number. - - Extensions have to be registered to this pool by calling :func:`Add` or - :func:`AddExtensionDescriptor`. - - Args: - message_descriptor (Descriptor): descriptor of the extended message. - number (int): Number of the extension field. - - Returns: - FieldDescriptor: The descriptor for the extension. - - Raises: - KeyError: when no extension with the given number is known for the - specified message. - """ - try: - return self._extensions_by_number[message_descriptor][number] - except KeyError: - self._TryLoadExtensionFromDB(message_descriptor, number) - return self._extensions_by_number[message_descriptor][number] - - def FindAllExtensions(self, message_descriptor): - """Gets all the known extensions of a given message. - - Extensions have to be registered to this pool by build related - :func:`Add` or :func:`AddExtensionDescriptor`. - - Args: - message_descriptor (Descriptor): Descriptor of the extended message. - - Returns: - list[FieldDescriptor]: Field descriptors describing the extensions. - """ - # Fallback to descriptor db if FindAllExtensionNumbers is provided. - if self._descriptor_db and hasattr( - self._descriptor_db, 'FindAllExtensionNumbers'): - full_name = message_descriptor.full_name - all_numbers = self._descriptor_db.FindAllExtensionNumbers(full_name) - for number in all_numbers: - if number in self._extensions_by_number[message_descriptor]: - continue - self._TryLoadExtensionFromDB(message_descriptor, number) - - return list(self._extensions_by_number[message_descriptor].values()) - - def _TryLoadExtensionFromDB(self, message_descriptor, number): - """Try to Load extensions from descriptor db. - - Args: - message_descriptor: descriptor of the extended message. - number: the extension number that needs to be loaded. - """ - if not self._descriptor_db: - return - # Only supported when FindFileContainingExtension is provided. - if not hasattr( - self._descriptor_db, 'FindFileContainingExtension'): - return - - full_name = message_descriptor.full_name - file_proto = self._descriptor_db.FindFileContainingExtension( - full_name, number) - - if file_proto is None: - return - - try: - self._ConvertFileProtoToFileDescriptor(file_proto) - except: - warn_msg = ('Unable to load proto file %s for extension number %d.' % - (file_proto.name, number)) - warnings.warn(warn_msg, RuntimeWarning) - - def FindServiceByName(self, full_name): - """Loads the named service descriptor from the pool. - - Args: - full_name (str): The full name of the service descriptor to load. - - Returns: - ServiceDescriptor: The service descriptor for the named service. - - Raises: - KeyError: if the service cannot be found in the pool. - """ - full_name = _NormalizeFullyQualifiedName(full_name) - if full_name not in self._service_descriptors: - self._FindFileContainingSymbolInDb(full_name) - return self._service_descriptors[full_name] - - def FindMethodByName(self, full_name): - """Loads the named service method descriptor from the pool. - - Args: - full_name (str): The full name of the method descriptor to load. - - Returns: - MethodDescriptor: The method descriptor for the service method. - - Raises: - KeyError: if the method cannot be found in the pool. - """ - full_name = _NormalizeFullyQualifiedName(full_name) - service_name, _, method_name = full_name.rpartition('.') - service_descriptor = self.FindServiceByName(service_name) - return service_descriptor.methods_by_name[method_name] - - def _FindFileContainingSymbolInDb(self, symbol): - """Finds the file in descriptor DB containing the specified symbol. - - Args: - symbol (str): The name of the symbol to search for. - - Returns: - FileDescriptor: The file that contains the specified symbol. - - Raises: - KeyError: if the file cannot be found in the descriptor database. - """ - try: - file_proto = self._internal_db.FindFileContainingSymbol(symbol) - except KeyError as error: - if self._descriptor_db: - file_proto = self._descriptor_db.FindFileContainingSymbol(symbol) - else: - raise error - if not file_proto: - raise KeyError('Cannot find a file containing %s' % symbol) - return self._ConvertFileProtoToFileDescriptor(file_proto) - - def _ConvertFileProtoToFileDescriptor(self, file_proto): - """Creates a FileDescriptor from a proto or returns a cached copy. - - This method also has the side effect of loading all the symbols found in - the file into the appropriate dictionaries in the pool. - - Args: - file_proto: The proto to convert. - - Returns: - A FileDescriptor matching the passed in proto. - """ - if file_proto.name not in self._file_descriptors: - built_deps = list(self._GetDeps(file_proto.dependency)) - direct_deps = [self.FindFileByName(n) for n in file_proto.dependency] - public_deps = [direct_deps[i] for i in file_proto.public_dependency] - - file_descriptor = descriptor.FileDescriptor( - pool=self, - name=file_proto.name, - package=file_proto.package, - syntax=file_proto.syntax, - options=_OptionsOrNone(file_proto), - serialized_pb=file_proto.SerializeToString(), - dependencies=direct_deps, - public_dependencies=public_deps, - # pylint: disable=protected-access - create_key=descriptor._internal_create_key) - scope = {} - - # This loop extracts all the message and enum types from all the - # dependencies of the file_proto. This is necessary to create the - # scope of available message types when defining the passed in - # file proto. - for dependency in built_deps: - scope.update(self._ExtractSymbols( - dependency.message_types_by_name.values())) - scope.update((_PrefixWithDot(enum.full_name), enum) - for enum in dependency.enum_types_by_name.values()) - - for message_type in file_proto.message_type: - message_desc = self._ConvertMessageDescriptor( - message_type, file_proto.package, file_descriptor, scope, - file_proto.syntax) - file_descriptor.message_types_by_name[message_desc.name] = ( - message_desc) - - for enum_type in file_proto.enum_type: - file_descriptor.enum_types_by_name[enum_type.name] = ( - self._ConvertEnumDescriptor(enum_type, file_proto.package, - file_descriptor, None, scope, True)) - - for index, extension_proto in enumerate(file_proto.extension): - extension_desc = self._MakeFieldDescriptor( - extension_proto, file_proto.package, index, file_descriptor, - is_extension=True) - extension_desc.containing_type = self._GetTypeFromScope( - file_descriptor.package, extension_proto.extendee, scope) - self._SetFieldType(extension_proto, extension_desc, - file_descriptor.package, scope) - file_descriptor.extensions_by_name[extension_desc.name] = ( - extension_desc) - self._file_desc_by_toplevel_extension[extension_desc.full_name] = ( - file_descriptor) - - for desc_proto in file_proto.message_type: - self._SetAllFieldTypes(file_proto.package, desc_proto, scope) - - if file_proto.package: - desc_proto_prefix = _PrefixWithDot(file_proto.package) - else: - desc_proto_prefix = '' - - for desc_proto in file_proto.message_type: - desc = self._GetTypeFromScope( - desc_proto_prefix, desc_proto.name, scope) - file_descriptor.message_types_by_name[desc_proto.name] = desc - - for index, service_proto in enumerate(file_proto.service): - file_descriptor.services_by_name[service_proto.name] = ( - self._MakeServiceDescriptor(service_proto, index, scope, - file_proto.package, file_descriptor)) - - self._file_descriptors[file_proto.name] = file_descriptor - - # Add extensions to the pool - file_desc = self._file_descriptors[file_proto.name] - for extension in file_desc.extensions_by_name.values(): - self._AddExtensionDescriptor(extension) - for message_type in file_desc.message_types_by_name.values(): - for extension in message_type.extensions: - self._AddExtensionDescriptor(extension) - - return file_desc - - def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None, - scope=None, syntax=None): - """Adds the proto to the pool in the specified package. - - Args: - desc_proto: The descriptor_pb2.DescriptorProto protobuf message. - package: The package the proto should be located in. - file_desc: The file containing this message. - scope: Dict mapping short and full symbols to message and enum types. - syntax: string indicating syntax of the file ("proto2" or "proto3") - - Returns: - The added descriptor. - """ - - if package: - desc_name = '.'.join((package, desc_proto.name)) - else: - desc_name = desc_proto.name - - if file_desc is None: - file_name = None - else: - file_name = file_desc.name - - if scope is None: - scope = {} - - nested = [ - self._ConvertMessageDescriptor( - nested, desc_name, file_desc, scope, syntax) - for nested in desc_proto.nested_type] - enums = [ - self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, - scope, False) - for enum in desc_proto.enum_type] - fields = [self._MakeFieldDescriptor(field, desc_name, index, file_desc) - for index, field in enumerate(desc_proto.field)] - extensions = [ - self._MakeFieldDescriptor(extension, desc_name, index, file_desc, - is_extension=True) - for index, extension in enumerate(desc_proto.extension)] - oneofs = [ - # pylint: disable=g-complex-comprehension - descriptor.OneofDescriptor( - desc.name, - '.'.join((desc_name, desc.name)), - index, - None, - [], - _OptionsOrNone(desc), - # pylint: disable=protected-access - create_key=descriptor._internal_create_key) - for index, desc in enumerate(desc_proto.oneof_decl) - ] - extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range] - if extension_ranges: - is_extendable = True - else: - is_extendable = False - desc = descriptor.Descriptor( - name=desc_proto.name, - full_name=desc_name, - filename=file_name, - containing_type=None, - fields=fields, - oneofs=oneofs, - nested_types=nested, - enum_types=enums, - extensions=extensions, - options=_OptionsOrNone(desc_proto), - is_extendable=is_extendable, - extension_ranges=extension_ranges, - file=file_desc, - serialized_start=None, - serialized_end=None, - syntax=syntax, - # pylint: disable=protected-access - create_key=descriptor._internal_create_key) - for nested in desc.nested_types: - nested.containing_type = desc - for enum in desc.enum_types: - enum.containing_type = desc - for field_index, field_desc in enumerate(desc_proto.field): - if field_desc.HasField('oneof_index'): - oneof_index = field_desc.oneof_index - oneofs[oneof_index].fields.append(fields[field_index]) - fields[field_index].containing_oneof = oneofs[oneof_index] - - scope[_PrefixWithDot(desc_name)] = desc - self._CheckConflictRegister(desc, desc.full_name, desc.file.name) - self._descriptors[desc_name] = desc - return desc - - def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None, - containing_type=None, scope=None, top_level=False): - """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf. - - Args: - enum_proto: The descriptor_pb2.EnumDescriptorProto protobuf message. - package: Optional package name for the new message EnumDescriptor. - file_desc: The file containing the enum descriptor. - containing_type: The type containing this enum. - scope: Scope containing available types. - top_level: If True, the enum is a top level symbol. If False, the enum - is defined inside a message. - - Returns: - The added descriptor - """ - - if package: - enum_name = '.'.join((package, enum_proto.name)) - else: - enum_name = enum_proto.name - - if file_desc is None: - file_name = None - else: - file_name = file_desc.name - - values = [self._MakeEnumValueDescriptor(value, index) - for index, value in enumerate(enum_proto.value)] - desc = descriptor.EnumDescriptor(name=enum_proto.name, - full_name=enum_name, - filename=file_name, - file=file_desc, - values=values, - containing_type=containing_type, - options=_OptionsOrNone(enum_proto), - # pylint: disable=protected-access - create_key=descriptor._internal_create_key) - scope['.%s' % enum_name] = desc - self._CheckConflictRegister(desc, desc.full_name, desc.file.name) - self._enum_descriptors[enum_name] = desc - - # Add top level enum values. - if top_level: - for value in values: - full_name = _NormalizeFullyQualifiedName( - '.'.join((package, value.name))) - self._CheckConflictRegister(value, full_name, file_name) - self._top_enum_values[full_name] = value - - return desc - - def _MakeFieldDescriptor(self, field_proto, message_name, index, - file_desc, is_extension=False): - """Creates a field descriptor from a FieldDescriptorProto. - - For message and enum type fields, this method will do a look up - in the pool for the appropriate descriptor for that type. If it - is unavailable, it will fall back to the _source function to - create it. If this type is still unavailable, construction will - fail. - - Args: - field_proto: The proto describing the field. - message_name: The name of the containing message. - index: Index of the field - file_desc: The file containing the field descriptor. - is_extension: Indication that this field is for an extension. - - Returns: - An initialized FieldDescriptor object - """ - - if message_name: - full_name = '.'.join((message_name, field_proto.name)) - else: - full_name = field_proto.name - - if field_proto.json_name: - json_name = field_proto.json_name - else: - json_name = None - - return descriptor.FieldDescriptor( - name=field_proto.name, - full_name=full_name, - index=index, - number=field_proto.number, - type=field_proto.type, - cpp_type=None, - message_type=None, - enum_type=None, - containing_type=None, - label=field_proto.label, - has_default_value=False, - default_value=None, - is_extension=is_extension, - extension_scope=None, - options=_OptionsOrNone(field_proto), - json_name=json_name, - file=file_desc, - # pylint: disable=protected-access - create_key=descriptor._internal_create_key) - - def _SetAllFieldTypes(self, package, desc_proto, scope): - """Sets all the descriptor's fields's types. - - This method also sets the containing types on any extensions. - - Args: - package: The current package of desc_proto. - desc_proto: The message descriptor to update. - scope: Enclosing scope of available types. - """ - - package = _PrefixWithDot(package) - - main_desc = self._GetTypeFromScope(package, desc_proto.name, scope) - - if package == '.': - nested_package = _PrefixWithDot(desc_proto.name) - else: - nested_package = '.'.join([package, desc_proto.name]) - - for field_proto, field_desc in zip(desc_proto.field, main_desc.fields): - self._SetFieldType(field_proto, field_desc, nested_package, scope) - - for extension_proto, extension_desc in ( - zip(desc_proto.extension, main_desc.extensions)): - extension_desc.containing_type = self._GetTypeFromScope( - nested_package, extension_proto.extendee, scope) - self._SetFieldType(extension_proto, extension_desc, nested_package, scope) - - for nested_type in desc_proto.nested_type: - self._SetAllFieldTypes(nested_package, nested_type, scope) - - def _SetFieldType(self, field_proto, field_desc, package, scope): - """Sets the field's type, cpp_type, message_type and enum_type. - - Args: - field_proto: Data about the field in proto format. - field_desc: The descriptor to modify. - package: The package the field's container is in. - scope: Enclosing scope of available types. - """ - if field_proto.type_name: - desc = self._GetTypeFromScope(package, field_proto.type_name, scope) - else: - desc = None - - if not field_proto.HasField('type'): - if isinstance(desc, descriptor.Descriptor): - field_proto.type = descriptor.FieldDescriptor.TYPE_MESSAGE - else: - field_proto.type = descriptor.FieldDescriptor.TYPE_ENUM - - field_desc.cpp_type = descriptor.FieldDescriptor.ProtoTypeToCppProtoType( - field_proto.type) - - if (field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE - or field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP): - field_desc.message_type = desc - - if field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: - field_desc.enum_type = desc - - if field_proto.label == descriptor.FieldDescriptor.LABEL_REPEATED: - field_desc.has_default_value = False - field_desc.default_value = [] - elif field_proto.HasField('default_value'): - field_desc.has_default_value = True - if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or - field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT): - field_desc.default_value = float(field_proto.default_value) - elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING: - field_desc.default_value = field_proto.default_value - elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL: - field_desc.default_value = field_proto.default_value.lower() == 'true' - elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: - field_desc.default_value = field_desc.enum_type.values_by_name[ - field_proto.default_value].number - elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES: - field_desc.default_value = text_encoding.CUnescape( - field_proto.default_value) - elif field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE: - field_desc.default_value = None - else: - # All other types are of the "int" type. - field_desc.default_value = int(field_proto.default_value) - else: - field_desc.has_default_value = False - if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or - field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT): - field_desc.default_value = 0.0 - elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING: - field_desc.default_value = u'' - elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL: - field_desc.default_value = False - elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM: - field_desc.default_value = field_desc.enum_type.values[0].number - elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES: - field_desc.default_value = b'' - elif field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE: - field_desc.default_value = None - elif field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP: - field_desc.default_value = None - else: - # All other types are of the "int" type. - field_desc.default_value = 0 - - field_desc.type = field_proto.type - - def _MakeEnumValueDescriptor(self, value_proto, index): - """Creates a enum value descriptor object from a enum value proto. - - Args: - value_proto: The proto describing the enum value. - index: The index of the enum value. - - Returns: - An initialized EnumValueDescriptor object. - """ - - return descriptor.EnumValueDescriptor( - name=value_proto.name, - index=index, - number=value_proto.number, - options=_OptionsOrNone(value_proto), - type=None, - # pylint: disable=protected-access - create_key=descriptor._internal_create_key) - - def _MakeServiceDescriptor(self, service_proto, service_index, scope, - package, file_desc): - """Make a protobuf ServiceDescriptor given a ServiceDescriptorProto. - - Args: - service_proto: The descriptor_pb2.ServiceDescriptorProto protobuf message. - service_index: The index of the service in the File. - scope: Dict mapping short and full symbols to message and enum types. - package: Optional package name for the new message EnumDescriptor. - file_desc: The file containing the service descriptor. - - Returns: - The added descriptor. - """ - - if package: - service_name = '.'.join((package, service_proto.name)) - else: - service_name = service_proto.name - - methods = [self._MakeMethodDescriptor(method_proto, service_name, package, - scope, index) - for index, method_proto in enumerate(service_proto.method)] - desc = descriptor.ServiceDescriptor( - name=service_proto.name, - full_name=service_name, - index=service_index, - methods=methods, - options=_OptionsOrNone(service_proto), - file=file_desc, - # pylint: disable=protected-access - create_key=descriptor._internal_create_key) - self._CheckConflictRegister(desc, desc.full_name, desc.file.name) - self._service_descriptors[service_name] = desc - return desc - - def _MakeMethodDescriptor(self, method_proto, service_name, package, scope, - index): - """Creates a method descriptor from a MethodDescriptorProto. - - Args: - method_proto: The proto describing the method. - service_name: The name of the containing service. - package: Optional package name to look up for types. - scope: Scope containing available types. - index: Index of the method in the service. - - Returns: - An initialized MethodDescriptor object. - """ - full_name = '.'.join((service_name, method_proto.name)) - input_type = self._GetTypeFromScope( - package, method_proto.input_type, scope) - output_type = self._GetTypeFromScope( - package, method_proto.output_type, scope) - return descriptor.MethodDescriptor( - name=method_proto.name, - full_name=full_name, - index=index, - containing_service=None, - input_type=input_type, - output_type=output_type, - client_streaming=method_proto.client_streaming, - server_streaming=method_proto.server_streaming, - options=_OptionsOrNone(method_proto), - # pylint: disable=protected-access - create_key=descriptor._internal_create_key) - - def _ExtractSymbols(self, descriptors): - """Pulls out all the symbols from descriptor protos. - - Args: - descriptors: The messages to extract descriptors from. - Yields: - A two element tuple of the type name and descriptor object. - """ - - for desc in descriptors: - yield (_PrefixWithDot(desc.full_name), desc) - for symbol in self._ExtractSymbols(desc.nested_types): - yield symbol - for enum in desc.enum_types: - yield (_PrefixWithDot(enum.full_name), enum) - - def _GetDeps(self, dependencies, visited=None): - """Recursively finds dependencies for file protos. - - Args: - dependencies: The names of the files being depended on. - visited: The names of files already found. - - Yields: - Each direct and indirect dependency. - """ - - visited = visited or set() - for dependency in dependencies: - if dependency not in visited: - visited.add(dependency) - dep_desc = self.FindFileByName(dependency) - yield dep_desc - public_files = [d.name for d in dep_desc.public_dependencies] - yield from self._GetDeps(public_files, visited) - - def _GetTypeFromScope(self, package, type_name, scope): - """Finds a given type name in the current scope. - - Args: - package: The package the proto should be located in. - type_name: The name of the type to be found in the scope. - scope: Dict mapping short and full symbols to message and enum types. - - Returns: - The descriptor for the requested type. - """ - if type_name not in scope: - components = _PrefixWithDot(package).split('.') - while components: - possible_match = '.'.join(components + [type_name]) - if possible_match in scope: - type_name = possible_match - break - else: - components.pop(-1) - return scope[type_name] - - -def _PrefixWithDot(name): - return name if name.startswith('.') else '.%s' % name - - -if _USE_C_DESCRIPTORS: - # TODO(amauryfa): This pool could be constructed from Python code, when we - # support a flag like 'use_cpp_generated_pool=True'. - # pylint: disable=protected-access - _DEFAULT = descriptor._message.default_pool -else: - _DEFAULT = DescriptorPool() - - -def Default(): - return _DEFAULT diff --git a/scripts/protobuf3/protobuf3/duration_pb2.py b/scripts/protobuf3/protobuf3/duration_pb2.py deleted file mode 100644 index a8ecc07..0000000 --- a/scripts/protobuf3/protobuf3/duration_pb2.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/duration.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1egoogle/protobuf/duration.proto\x12\x0fgoogle.protobuf\"*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x83\x01\n\x13\x63om.google.protobufB\rDurationProtoP\x01Z1google.golang.org/protobuf/types/known/durationpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.duration_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\rDurationProtoP\001Z1google.golang.org/protobuf/types/known/durationpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' - _DURATION._serialized_start=51 - _DURATION._serialized_end=93 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/empty_pb2.py b/scripts/protobuf3/protobuf3/empty_pb2.py deleted file mode 100644 index 0b4d554..0000000 --- a/scripts/protobuf3/protobuf3/empty_pb2.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/empty.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bgoogle/protobuf/empty.proto\x12\x0fgoogle.protobuf\"\x07\n\x05\x45mptyB}\n\x13\x63om.google.protobufB\nEmptyProtoP\x01Z.google.golang.org/protobuf/types/known/emptypb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.empty_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\nEmptyProtoP\001Z.google.golang.org/protobuf/types/known/emptypb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' - _EMPTY._serialized_start=48 - _EMPTY._serialized_end=55 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/field_mask_pb2.py b/scripts/protobuf3/protobuf3/field_mask_pb2.py deleted file mode 100644 index 80a4e96..0000000 --- a/scripts/protobuf3/protobuf3/field_mask_pb2.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/field_mask.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n google/protobuf/field_mask.proto\x12\x0fgoogle.protobuf\"\x1a\n\tFieldMask\x12\r\n\x05paths\x18\x01 \x03(\tB\x85\x01\n\x13\x63om.google.protobufB\x0e\x46ieldMaskProtoP\x01Z2google.golang.org/protobuf/types/known/fieldmaskpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.field_mask_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\016FieldMaskProtoP\001Z2google.golang.org/protobuf/types/known/fieldmaskpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' - _FIELDMASK._serialized_start=53 - _FIELDMASK._serialized_end=79 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/internal/__init__.py b/scripts/protobuf3/protobuf3/internal/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/protobuf3/protobuf3/internal/_parameterized.py b/scripts/protobuf3/protobuf3/internal/_parameterized.py deleted file mode 100644 index afdbb78..0000000 --- a/scripts/protobuf3/protobuf3/internal/_parameterized.py +++ /dev/null @@ -1,443 +0,0 @@ -#! /usr/bin/env python -# -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Adds support for parameterized tests to Python's unittest TestCase class. - -A parameterized test is a method in a test case that is invoked with different -argument tuples. - -A simple example: - - class AdditionExample(parameterized.TestCase): - @parameterized.parameters( - (1, 2, 3), - (4, 5, 9), - (1, 1, 3)) - def testAddition(self, op1, op2, result): - self.assertEqual(result, op1 + op2) - - -Each invocation is a separate test case and properly isolated just -like a normal test method, with its own setUp/tearDown cycle. In the -example above, there are three separate testcases, one of which will -fail due to an assertion error (1 + 1 != 3). - -Parameters for individual test cases can be tuples (with positional parameters) -or dictionaries (with named parameters): - - class AdditionExample(parameterized.TestCase): - @parameterized.parameters( - {'op1': 1, 'op2': 2, 'result': 3}, - {'op1': 4, 'op2': 5, 'result': 9}, - ) - def testAddition(self, op1, op2, result): - self.assertEqual(result, op1 + op2) - -If a parameterized test fails, the error message will show the -original test name (which is modified internally) and the arguments -for the specific invocation, which are part of the string returned by -the shortDescription() method on test cases. - -The id method of the test, used internally by the unittest framework, -is also modified to show the arguments. To make sure that test names -stay the same across several invocations, object representations like - - >>> class Foo(object): - ... pass - >>> repr(Foo()) - '<__main__.Foo object at 0x23d8610>' - -are turned into '<__main__.Foo>'. For even more descriptive names, -especially in test logs, you can use the named_parameters decorator. In -this case, only tuples are supported, and the first parameters has to -be a string (or an object that returns an apt name when converted via -str()): - - class NamedExample(parameterized.TestCase): - @parameterized.named_parameters( - ('Normal', 'aa', 'aaa', True), - ('EmptyPrefix', '', 'abc', True), - ('BothEmpty', '', '', True)) - def testStartsWith(self, prefix, string, result): - self.assertEqual(result, strings.startswith(prefix)) - -Named tests also have the benefit that they can be run individually -from the command line: - - $ testmodule.py NamedExample.testStartsWithNormal - . - -------------------------------------------------------------------- - Ran 1 test in 0.000s - - OK - -Parameterized Classes -===================== -If invocation arguments are shared across test methods in a single -TestCase class, instead of decorating all test methods -individually, the class itself can be decorated: - - @parameterized.parameters( - (1, 2, 3) - (4, 5, 9)) - class ArithmeticTest(parameterized.TestCase): - def testAdd(self, arg1, arg2, result): - self.assertEqual(arg1 + arg2, result) - - def testSubtract(self, arg2, arg2, result): - self.assertEqual(result - arg1, arg2) - -Inputs from Iterables -===================== -If parameters should be shared across several test cases, or are dynamically -created from other sources, a single non-tuple iterable can be passed into -the decorator. This iterable will be used to obtain the test cases: - - class AdditionExample(parameterized.TestCase): - @parameterized.parameters( - c.op1, c.op2, c.result for c in testcases - ) - def testAddition(self, op1, op2, result): - self.assertEqual(result, op1 + op2) - - -Single-Argument Test Methods -============================ -If a test method takes only one argument, the single argument does not need to -be wrapped into a tuple: - - class NegativeNumberExample(parameterized.TestCase): - @parameterized.parameters( - -1, -3, -4, -5 - ) - def testIsNegative(self, arg): - self.assertTrue(IsNegative(arg)) -""" - -__author__ = 'tmarek@google.com (Torsten Marek)' - -import functools -import re -import types -import unittest -import uuid - -try: - # Since python 3 - import collections.abc as collections_abc -except ImportError: - # Won't work after python 3.8 - import collections as collections_abc - -ADDR_RE = re.compile(r'\<([a-zA-Z0-9_\-\.]+) object at 0x[a-fA-F0-9]+\>') -_SEPARATOR = uuid.uuid1().hex -_FIRST_ARG = object() -_ARGUMENT_REPR = object() - - -def _CleanRepr(obj): - return ADDR_RE.sub(r'<\1>', repr(obj)) - - -# Helper function formerly from the unittest module, removed from it in -# Python 2.7. -def _StrClass(cls): - return '%s.%s' % (cls.__module__, cls.__name__) - - -def _NonStringIterable(obj): - return (isinstance(obj, collections_abc.Iterable) and - not isinstance(obj, str)) - - -def _FormatParameterList(testcase_params): - if isinstance(testcase_params, collections_abc.Mapping): - return ', '.join('%s=%s' % (argname, _CleanRepr(value)) - for argname, value in testcase_params.items()) - elif _NonStringIterable(testcase_params): - return ', '.join(map(_CleanRepr, testcase_params)) - else: - return _FormatParameterList((testcase_params,)) - - -class _ParameterizedTestIter(object): - """Callable and iterable class for producing new test cases.""" - - def __init__(self, test_method, testcases, naming_type): - """Returns concrete test functions for a test and a list of parameters. - - The naming_type is used to determine the name of the concrete - functions as reported by the unittest framework. If naming_type is - _FIRST_ARG, the testcases must be tuples, and the first element must - have a string representation that is a valid Python identifier. - - Args: - test_method: The decorated test method. - testcases: (list of tuple/dict) A list of parameter - tuples/dicts for individual test invocations. - naming_type: The test naming type, either _NAMED or _ARGUMENT_REPR. - """ - self._test_method = test_method - self.testcases = testcases - self._naming_type = naming_type - - def __call__(self, *args, **kwargs): - raise RuntimeError('You appear to be running a parameterized test case ' - 'without having inherited from parameterized.' - 'TestCase. This is bad because none of ' - 'your test cases are actually being run.') - - def __iter__(self): - test_method = self._test_method - naming_type = self._naming_type - - def MakeBoundParamTest(testcase_params): - @functools.wraps(test_method) - def BoundParamTest(self): - if isinstance(testcase_params, collections_abc.Mapping): - test_method(self, **testcase_params) - elif _NonStringIterable(testcase_params): - test_method(self, *testcase_params) - else: - test_method(self, testcase_params) - - if naming_type is _FIRST_ARG: - # Signal the metaclass that the name of the test function is unique - # and descriptive. - BoundParamTest.__x_use_name__ = True - BoundParamTest.__name__ += str(testcase_params[0]) - testcase_params = testcase_params[1:] - elif naming_type is _ARGUMENT_REPR: - # __x_extra_id__ is used to pass naming information to the __new__ - # method of TestGeneratorMetaclass. - # The metaclass will make sure to create a unique, but nondescriptive - # name for this test. - BoundParamTest.__x_extra_id__ = '(%s)' % ( - _FormatParameterList(testcase_params),) - else: - raise RuntimeError('%s is not a valid naming type.' % (naming_type,)) - - BoundParamTest.__doc__ = '%s(%s)' % ( - BoundParamTest.__name__, _FormatParameterList(testcase_params)) - if test_method.__doc__: - BoundParamTest.__doc__ += '\n%s' % (test_method.__doc__,) - return BoundParamTest - return (MakeBoundParamTest(c) for c in self.testcases) - - -def _IsSingletonList(testcases): - """True iff testcases contains only a single non-tuple element.""" - return len(testcases) == 1 and not isinstance(testcases[0], tuple) - - -def _ModifyClass(class_object, testcases, naming_type): - assert not getattr(class_object, '_id_suffix', None), ( - 'Cannot add parameters to %s,' - ' which already has parameterized methods.' % (class_object,)) - class_object._id_suffix = id_suffix = {} - # We change the size of __dict__ while we iterate over it, - # which Python 3.x will complain about, so use copy(). - for name, obj in class_object.__dict__.copy().items(): - if (name.startswith(unittest.TestLoader.testMethodPrefix) - and isinstance(obj, types.FunctionType)): - delattr(class_object, name) - methods = {} - _UpdateClassDictForParamTestCase( - methods, id_suffix, name, - _ParameterizedTestIter(obj, testcases, naming_type)) - for name, meth in methods.items(): - setattr(class_object, name, meth) - - -def _ParameterDecorator(naming_type, testcases): - """Implementation of the parameterization decorators. - - Args: - naming_type: The naming type. - testcases: Testcase parameters. - - Returns: - A function for modifying the decorated object. - """ - def _Apply(obj): - if isinstance(obj, type): - _ModifyClass( - obj, - list(testcases) if not isinstance(testcases, collections_abc.Sequence) - else testcases, - naming_type) - return obj - else: - return _ParameterizedTestIter(obj, testcases, naming_type) - - if _IsSingletonList(testcases): - assert _NonStringIterable(testcases[0]), ( - 'Single parameter argument must be a non-string iterable') - testcases = testcases[0] - - return _Apply - - -def parameters(*testcases): # pylint: disable=invalid-name - """A decorator for creating parameterized tests. - - See the module docstring for a usage example. - Args: - *testcases: Parameters for the decorated method, either a single - iterable, or a list of tuples/dicts/objects (for tests - with only one argument). - - Returns: - A test generator to be handled by TestGeneratorMetaclass. - """ - return _ParameterDecorator(_ARGUMENT_REPR, testcases) - - -def named_parameters(*testcases): # pylint: disable=invalid-name - """A decorator for creating parameterized tests. - - See the module docstring for a usage example. The first element of - each parameter tuple should be a string and will be appended to the - name of the test method. - - Args: - *testcases: Parameters for the decorated method, either a single - iterable, or a list of tuples. - - Returns: - A test generator to be handled by TestGeneratorMetaclass. - """ - return _ParameterDecorator(_FIRST_ARG, testcases) - - -class TestGeneratorMetaclass(type): - """Metaclass for test cases with test generators. - - A test generator is an iterable in a testcase that produces callables. These - callables must be single-argument methods. These methods are injected into - the class namespace and the original iterable is removed. If the name of the - iterable conforms to the test pattern, the injected methods will be picked - up as tests by the unittest framework. - - In general, it is supposed to be used in conjunction with the - parameters decorator. - """ - - def __new__(mcs, class_name, bases, dct): - dct['_id_suffix'] = id_suffix = {} - for name, obj in dct.copy().items(): - if (name.startswith(unittest.TestLoader.testMethodPrefix) and - _NonStringIterable(obj)): - iterator = iter(obj) - dct.pop(name) - _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator) - - return type.__new__(mcs, class_name, bases, dct) - - -def _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator): - """Adds individual test cases to a dictionary. - - Args: - dct: The target dictionary. - id_suffix: The dictionary for mapping names to test IDs. - name: The original name of the test case. - iterator: The iterator generating the individual test cases. - """ - for idx, func in enumerate(iterator): - assert callable(func), 'Test generators must yield callables, got %r' % ( - func,) - if getattr(func, '__x_use_name__', False): - new_name = func.__name__ - else: - new_name = '%s%s%d' % (name, _SEPARATOR, idx) - assert new_name not in dct, ( - 'Name of parameterized test case "%s" not unique' % (new_name,)) - dct[new_name] = func - id_suffix[new_name] = getattr(func, '__x_extra_id__', '') - - -class TestCase(unittest.TestCase, metaclass=TestGeneratorMetaclass): - """Base class for test cases using the parameters decorator.""" - - def _OriginalName(self): - return self._testMethodName.split(_SEPARATOR)[0] - - def __str__(self): - return '%s (%s)' % (self._OriginalName(), _StrClass(self.__class__)) - - def id(self): # pylint: disable=invalid-name - """Returns the descriptive ID of the test. - - This is used internally by the unittesting framework to get a name - for the test to be used in reports. - - Returns: - The test id. - """ - return '%s.%s%s' % (_StrClass(self.__class__), - self._OriginalName(), - self._id_suffix.get(self._testMethodName, '')) - - -def CoopTestCase(other_base_class): - """Returns a new base class with a cooperative metaclass base. - - This enables the TestCase to be used in combination - with other base classes that have custom metaclasses, such as - mox.MoxTestBase. - - Only works with metaclasses that do not override type.__new__. - - Example: - - import google3 - import mox - - from google3.testing.pybase import parameterized - - class ExampleTest(parameterized.CoopTestCase(mox.MoxTestBase)): - ... - - Args: - other_base_class: (class) A test case base class. - - Returns: - A new class object. - """ - metaclass = type( - 'CoopMetaclass', - (other_base_class.__metaclass__, - TestGeneratorMetaclass), {}) - return metaclass( - 'CoopTestCase', - (other_base_class, TestCase), {}) diff --git a/scripts/protobuf3/protobuf3/internal/api_implementation.py b/scripts/protobuf3/protobuf3/internal/api_implementation.py deleted file mode 100644 index 7fef237..0000000 --- a/scripts/protobuf3/protobuf3/internal/api_implementation.py +++ /dev/null @@ -1,112 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Determine which implementation of the protobuf API is used in this process. -""" - -import os -import sys -import warnings - -try: - # pylint: disable=g-import-not-at-top - from google.protobuf.internal import _api_implementation - # The compile-time constants in the _api_implementation module can be used to - # switch to a certain implementation of the Python API at build time. - _api_version = _api_implementation.api_version -except ImportError: - _api_version = -1 # Unspecified by compiler flags. - -if _api_version == 1: - raise ValueError('api_version=1 is no longer supported.') - - -_default_implementation_type = ('cpp' if _api_version > 0 else 'python') - - -# This environment variable can be used to switch to a certain implementation -# of the Python API, overriding the compile-time constants in the -# _api_implementation module. Right now only 'python' and 'cpp' are valid -# values. Any other value will be ignored. -_implementation_type = os.getenv('PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION', - _default_implementation_type) - -if _implementation_type != 'python': - _implementation_type = 'cpp' - -if 'PyPy' in sys.version and _implementation_type == 'cpp': - warnings.warn('PyPy does not work yet with cpp protocol buffers. ' - 'Falling back to the python implementation.') - _implementation_type = 'python' - - -# Detect if serialization should be deterministic by default -try: - # The presence of this module in a build allows the proto implementation to - # be upgraded merely via build deps. - # - # NOTE: Merely importing this automatically enables deterministic proto - # serialization for C++ code, but we still need to export it as a boolean so - # that we can do the same for `_implementation_type == 'python'`. - # - # NOTE2: It is possible for C++ code to enable deterministic serialization by - # default _without_ affecting Python code, if the C++ implementation is not in - # use by this module. That is intended behavior, so we don't actually expose - # this boolean outside of this module. - # - # pylint: disable=g-import-not-at-top,unused-import - from google.protobuf import enable_deterministic_proto_serialization - _python_deterministic_proto_serialization = True -except ImportError: - _python_deterministic_proto_serialization = False - - -# Usage of this function is discouraged. Clients shouldn't care which -# implementation of the API is in use. Note that there is no guarantee -# that differences between APIs will be maintained. -# Please don't use this function if possible. -def Type(): - return _implementation_type - - -def _SetType(implementation_type): - """Never use! Only for protobuf benchmark.""" - global _implementation_type - _implementation_type = implementation_type - - -# See comment on 'Type' above. -def Version(): - return 2 - - -# For internal use only -def IsPythonDefaultSerializationDeterministic(): - return _python_deterministic_proto_serialization diff --git a/scripts/protobuf3/protobuf3/internal/builder.py b/scripts/protobuf3/protobuf3/internal/builder.py deleted file mode 100644 index 64353ee..0000000 --- a/scripts/protobuf3/protobuf3/internal/builder.py +++ /dev/null @@ -1,130 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Builds descriptors, message classes and services for generated _pb2.py. - -This file is only called in python generated _pb2.py files. It builds -descriptors, message classes and services that users can directly use -in generated code. -""" - -__author__ = 'jieluo@google.com (Jie Luo)' - -from google.protobuf.internal import enum_type_wrapper -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import symbol_database as _symbol_database - -_sym_db = _symbol_database.Default() - - -def BuildMessageAndEnumDescriptors(file_des, module): - """Builds message and enum descriptors. - - Args: - file_des: FileDescriptor of the .proto file - module: Generated _pb2 module - """ - - def BuildNestedDescriptors(msg_des, prefix): - for (name, nested_msg) in msg_des.nested_types_by_name.items(): - module_name = prefix + name.upper() - module[module_name] = nested_msg - BuildNestedDescriptors(nested_msg, module_name + '_') - for enum_des in msg_des.enum_types: - module[prefix + enum_des.name.upper()] = enum_des - - for (name, msg_des) in file_des.message_types_by_name.items(): - module_name = '_' + name.upper() - module[module_name] = msg_des - BuildNestedDescriptors(msg_des, module_name + '_') - - -def BuildTopDescriptorsAndMessages(file_des, module_name, module): - """Builds top level descriptors and message classes. - - Args: - file_des: FileDescriptor of the .proto file - module_name: str, the name of generated _pb2 module - module: Generated _pb2 module - """ - - def BuildMessage(msg_des): - create_dict = {} - for (name, nested_msg) in msg_des.nested_types_by_name.items(): - create_dict[name] = BuildMessage(nested_msg) - create_dict['DESCRIPTOR'] = msg_des - create_dict['__module__'] = module_name - message_class = _reflection.GeneratedProtocolMessageType( - msg_des.name, (_message.Message,), create_dict) - _sym_db.RegisterMessage(message_class) - return message_class - - # top level enums - for (name, enum_des) in file_des.enum_types_by_name.items(): - module['_' + name.upper()] = enum_des - module[name] = enum_type_wrapper.EnumTypeWrapper(enum_des) - for enum_value in enum_des.values: - module[enum_value.name] = enum_value.number - - # top level extensions - for (name, extension_des) in file_des.extensions_by_name.items(): - module[name.upper() + '_FIELD_NUMBER'] = extension_des.number - module[name] = extension_des - - # services - for (name, service) in file_des.services_by_name.items(): - module['_' + name.upper()] = service - - # Build messages. - for (name, msg_des) in file_des.message_types_by_name.items(): - module[name] = BuildMessage(msg_des) - - -def BuildServices(file_des, module_name, module): - """Builds services classes and services stub class. - - Args: - file_des: FileDescriptor of the .proto file - module_name: str, the name of generated _pb2 module - module: Generated _pb2 module - """ - # pylint: disable=g-import-not-at-top - from google.protobuf import service as _service - from google.protobuf import service_reflection - # pylint: enable=g-import-not-at-top - for (name, service) in file_des.services_by_name.items(): - module[name] = service_reflection.GeneratedServiceType( - name, (_service.Service,), - dict(DESCRIPTOR=service, __module__=module_name)) - stub_name = name + '_Stub' - module[stub_name] = service_reflection.GeneratedServiceStubType( - stub_name, (module[name],), - dict(DESCRIPTOR=service, __module__=module_name)) diff --git a/scripts/protobuf3/protobuf3/internal/containers.py b/scripts/protobuf3/protobuf3/internal/containers.py deleted file mode 100644 index 29fbb53..0000000 --- a/scripts/protobuf3/protobuf3/internal/containers.py +++ /dev/null @@ -1,710 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Contains container classes to represent different protocol buffer types. - -This file defines container classes which represent categories of protocol -buffer field types which need extra maintenance. Currently these categories -are: - -- Repeated scalar fields - These are all repeated fields which aren't - composite (e.g. they are of simple types like int32, string, etc). -- Repeated composite fields - Repeated fields which are composite. This - includes groups and nested messages. -""" - -import collections.abc -import copy -import pickle -from typing import ( - Any, - Iterable, - Iterator, - List, - MutableMapping, - MutableSequence, - NoReturn, - Optional, - Sequence, - TypeVar, - Union, - overload, -) - - -_T = TypeVar('_T') -_K = TypeVar('_K') -_V = TypeVar('_V') - - -class BaseContainer(Sequence[_T]): - """Base container class.""" - - # Minimizes memory usage and disallows assignment to other attributes. - __slots__ = ['_message_listener', '_values'] - - def __init__(self, message_listener: Any) -> None: - """ - Args: - message_listener: A MessageListener implementation. - The RepeatedScalarFieldContainer will call this object's - Modified() method when it is modified. - """ - self._message_listener = message_listener - self._values = [] - - @overload - def __getitem__(self, key: int) -> _T: - ... - - @overload - def __getitem__(self, key: slice) -> List[_T]: - ... - - def __getitem__(self, key): - """Retrieves item by the specified key.""" - return self._values[key] - - def __len__(self) -> int: - """Returns the number of elements in the container.""" - return len(self._values) - - def __ne__(self, other: Any) -> bool: - """Checks if another instance isn't equal to this one.""" - # The concrete classes should define __eq__. - return not self == other - - __hash__ = None - - def __repr__(self) -> str: - return repr(self._values) - - def sort(self, *args, **kwargs) -> None: - # Continue to support the old sort_function keyword argument. - # This is expected to be a rare occurrence, so use LBYL to avoid - # the overhead of actually catching KeyError. - if 'sort_function' in kwargs: - kwargs['cmp'] = kwargs.pop('sort_function') - self._values.sort(*args, **kwargs) - - def reverse(self) -> None: - self._values.reverse() - - -# TODO(slebedev): Remove this. BaseContainer does *not* conform to -# MutableSequence, only its subclasses do. -collections.abc.MutableSequence.register(BaseContainer) - - -class RepeatedScalarFieldContainer(BaseContainer[_T], MutableSequence[_T]): - """Simple, type-checked, list-like container for holding repeated scalars.""" - - # Disallows assignment to other attributes. - __slots__ = ['_type_checker'] - - def __init__( - self, - message_listener: Any, - type_checker: Any, - ) -> None: - """Args: - - message_listener: A MessageListener implementation. The - RepeatedScalarFieldContainer will call this object's Modified() method - when it is modified. - type_checker: A type_checkers.ValueChecker instance to run on elements - inserted into this container. - """ - super().__init__(message_listener) - self._type_checker = type_checker - - def append(self, value: _T) -> None: - """Appends an item to the list. Similar to list.append().""" - self._values.append(self._type_checker.CheckValue(value)) - if not self._message_listener.dirty: - self._message_listener.Modified() - - def insert(self, key: int, value: _T) -> None: - """Inserts the item at the specified position. Similar to list.insert().""" - self._values.insert(key, self._type_checker.CheckValue(value)) - if not self._message_listener.dirty: - self._message_listener.Modified() - - def extend(self, elem_seq: Iterable[_T]) -> None: - """Extends by appending the given iterable. Similar to list.extend().""" - if elem_seq is None: - return - try: - elem_seq_iter = iter(elem_seq) - except TypeError: - if not elem_seq: - # silently ignore falsy inputs :-/. - # TODO(ptucker): Deprecate this behavior. b/18413862 - return - raise - - new_values = [self._type_checker.CheckValue(elem) for elem in elem_seq_iter] - if new_values: - self._values.extend(new_values) - self._message_listener.Modified() - - def MergeFrom( - self, - other: Union['RepeatedScalarFieldContainer[_T]', Iterable[_T]], - ) -> None: - """Appends the contents of another repeated field of the same type to this - one. We do not check the types of the individual fields. - """ - self._values.extend(other) - self._message_listener.Modified() - - def remove(self, elem: _T): - """Removes an item from the list. Similar to list.remove().""" - self._values.remove(elem) - self._message_listener.Modified() - - def pop(self, key: Optional[int] = -1) -> _T: - """Removes and returns an item at a given index. Similar to list.pop().""" - value = self._values[key] - self.__delitem__(key) - return value - - @overload - def __setitem__(self, key: int, value: _T) -> None: - ... - - @overload - def __setitem__(self, key: slice, value: Iterable[_T]) -> None: - ... - - def __setitem__(self, key, value) -> None: - """Sets the item on the specified position.""" - if isinstance(key, slice): - if key.step is not None: - raise ValueError('Extended slices not supported') - self._values[key] = map(self._type_checker.CheckValue, value) - self._message_listener.Modified() - else: - self._values[key] = self._type_checker.CheckValue(value) - self._message_listener.Modified() - - def __delitem__(self, key: Union[int, slice]) -> None: - """Deletes the item at the specified position.""" - del self._values[key] - self._message_listener.Modified() - - def __eq__(self, other: Any) -> bool: - """Compares the current instance with another one.""" - if self is other: - return True - # Special case for the same type which should be common and fast. - if isinstance(other, self.__class__): - return other._values == self._values - # We are presumably comparing against some other sequence type. - return other == self._values - - def __deepcopy__( - self, - unused_memo: Any = None, - ) -> 'RepeatedScalarFieldContainer[_T]': - clone = RepeatedScalarFieldContainer( - copy.deepcopy(self._message_listener), self._type_checker) - clone.MergeFrom(self) - return clone - - def __reduce__(self, **kwargs) -> NoReturn: - raise pickle.PickleError( - "Can't pickle repeated scalar fields, convert to list first") - - -# TODO(slebedev): Constrain T to be a subtype of Message. -class RepeatedCompositeFieldContainer(BaseContainer[_T], MutableSequence[_T]): - """Simple, list-like container for holding repeated composite fields.""" - - # Disallows assignment to other attributes. - __slots__ = ['_message_descriptor'] - - def __init__(self, message_listener: Any, message_descriptor: Any) -> None: - """ - Note that we pass in a descriptor instead of the generated directly, - since at the time we construct a _RepeatedCompositeFieldContainer we - haven't yet necessarily initialized the type that will be contained in the - container. - - Args: - message_listener: A MessageListener implementation. - The RepeatedCompositeFieldContainer will call this object's - Modified() method when it is modified. - message_descriptor: A Descriptor instance describing the protocol type - that should be present in this container. We'll use the - _concrete_class field of this descriptor when the client calls add(). - """ - super().__init__(message_listener) - self._message_descriptor = message_descriptor - - def add(self, **kwargs: Any) -> _T: - """Adds a new element at the end of the list and returns it. Keyword - arguments may be used to initialize the element. - """ - new_element = self._message_descriptor._concrete_class(**kwargs) - new_element._SetListener(self._message_listener) - self._values.append(new_element) - if not self._message_listener.dirty: - self._message_listener.Modified() - return new_element - - def append(self, value: _T) -> None: - """Appends one element by copying the message.""" - new_element = self._message_descriptor._concrete_class() - new_element._SetListener(self._message_listener) - new_element.CopyFrom(value) - self._values.append(new_element) - if not self._message_listener.dirty: - self._message_listener.Modified() - - def insert(self, key: int, value: _T) -> None: - """Inserts the item at the specified position by copying.""" - new_element = self._message_descriptor._concrete_class() - new_element._SetListener(self._message_listener) - new_element.CopyFrom(value) - self._values.insert(key, new_element) - if not self._message_listener.dirty: - self._message_listener.Modified() - - def extend(self, elem_seq: Iterable[_T]) -> None: - """Extends by appending the given sequence of elements of the same type - - as this one, copying each individual message. - """ - message_class = self._message_descriptor._concrete_class - listener = self._message_listener - values = self._values - for message in elem_seq: - new_element = message_class() - new_element._SetListener(listener) - new_element.MergeFrom(message) - values.append(new_element) - listener.Modified() - - def MergeFrom( - self, - other: Union['RepeatedCompositeFieldContainer[_T]', Iterable[_T]], - ) -> None: - """Appends the contents of another repeated field of the same type to this - one, copying each individual message. - """ - self.extend(other) - - def remove(self, elem: _T) -> None: - """Removes an item from the list. Similar to list.remove().""" - self._values.remove(elem) - self._message_listener.Modified() - - def pop(self, key: Optional[int] = -1) -> _T: - """Removes and returns an item at a given index. Similar to list.pop().""" - value = self._values[key] - self.__delitem__(key) - return value - - @overload - def __setitem__(self, key: int, value: _T) -> None: - ... - - @overload - def __setitem__(self, key: slice, value: Iterable[_T]) -> None: - ... - - def __setitem__(self, key, value): - # This method is implemented to make RepeatedCompositeFieldContainer - # structurally compatible with typing.MutableSequence. It is - # otherwise unsupported and will always raise an error. - raise TypeError( - f'{self.__class__.__name__} object does not support item assignment') - - def __delitem__(self, key: Union[int, slice]) -> None: - """Deletes the item at the specified position.""" - del self._values[key] - self._message_listener.Modified() - - def __eq__(self, other: Any) -> bool: - """Compares the current instance with another one.""" - if self is other: - return True - if not isinstance(other, self.__class__): - raise TypeError('Can only compare repeated composite fields against ' - 'other repeated composite fields.') - return self._values == other._values - - -class ScalarMap(MutableMapping[_K, _V]): - """Simple, type-checked, dict-like container for holding repeated scalars.""" - - # Disallows assignment to other attributes. - __slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener', - '_entry_descriptor'] - - def __init__( - self, - message_listener: Any, - key_checker: Any, - value_checker: Any, - entry_descriptor: Any, - ) -> None: - """ - Args: - message_listener: A MessageListener implementation. - The ScalarMap will call this object's Modified() method when it - is modified. - key_checker: A type_checkers.ValueChecker instance to run on keys - inserted into this container. - value_checker: A type_checkers.ValueChecker instance to run on values - inserted into this container. - entry_descriptor: The MessageDescriptor of a map entry: key and value. - """ - self._message_listener = message_listener - self._key_checker = key_checker - self._value_checker = value_checker - self._entry_descriptor = entry_descriptor - self._values = {} - - def __getitem__(self, key: _K) -> _V: - try: - return self._values[key] - except KeyError: - key = self._key_checker.CheckValue(key) - val = self._value_checker.DefaultValue() - self._values[key] = val - return val - - def __contains__(self, item: _K) -> bool: - # We check the key's type to match the strong-typing flavor of the API. - # Also this makes it easier to match the behavior of the C++ implementation. - self._key_checker.CheckValue(item) - return item in self._values - - @overload - def get(self, key: _K) -> Optional[_V]: - ... - - @overload - def get(self, key: _K, default: _T) -> Union[_V, _T]: - ... - - # We need to override this explicitly, because our defaultdict-like behavior - # will make the default implementation (from our base class) always insert - # the key. - def get(self, key, default=None): - if key in self: - return self[key] - else: - return default - - def __setitem__(self, key: _K, value: _V) -> _T: - checked_key = self._key_checker.CheckValue(key) - checked_value = self._value_checker.CheckValue(value) - self._values[checked_key] = checked_value - self._message_listener.Modified() - - def __delitem__(self, key: _K) -> None: - del self._values[key] - self._message_listener.Modified() - - def __len__(self) -> int: - return len(self._values) - - def __iter__(self) -> Iterator[_K]: - return iter(self._values) - - def __repr__(self) -> str: - return repr(self._values) - - def MergeFrom(self, other: 'ScalarMap[_K, _V]') -> None: - self._values.update(other._values) - self._message_listener.Modified() - - def InvalidateIterators(self) -> None: - # It appears that the only way to reliably invalidate iterators to - # self._values is to ensure that its size changes. - original = self._values - self._values = original.copy() - original[None] = None - - # This is defined in the abstract base, but we can do it much more cheaply. - def clear(self) -> None: - self._values.clear() - self._message_listener.Modified() - - def GetEntryClass(self) -> Any: - return self._entry_descriptor._concrete_class - - -class MessageMap(MutableMapping[_K, _V]): - """Simple, type-checked, dict-like container for with submessage values.""" - - # Disallows assignment to other attributes. - __slots__ = ['_key_checker', '_values', '_message_listener', - '_message_descriptor', '_entry_descriptor'] - - def __init__( - self, - message_listener: Any, - message_descriptor: Any, - key_checker: Any, - entry_descriptor: Any, - ) -> None: - """ - Args: - message_listener: A MessageListener implementation. - The ScalarMap will call this object's Modified() method when it - is modified. - key_checker: A type_checkers.ValueChecker instance to run on keys - inserted into this container. - value_checker: A type_checkers.ValueChecker instance to run on values - inserted into this container. - entry_descriptor: The MessageDescriptor of a map entry: key and value. - """ - self._message_listener = message_listener - self._message_descriptor = message_descriptor - self._key_checker = key_checker - self._entry_descriptor = entry_descriptor - self._values = {} - - def __getitem__(self, key: _K) -> _V: - key = self._key_checker.CheckValue(key) - try: - return self._values[key] - except KeyError: - new_element = self._message_descriptor._concrete_class() - new_element._SetListener(self._message_listener) - self._values[key] = new_element - self._message_listener.Modified() - return new_element - - def get_or_create(self, key: _K) -> _V: - """get_or_create() is an alias for getitem (ie. map[key]). - - Args: - key: The key to get or create in the map. - - This is useful in cases where you want to be explicit that the call is - mutating the map. This can avoid lint errors for statements like this - that otherwise would appear to be pointless statements: - - msg.my_map[key] - """ - return self[key] - - @overload - def get(self, key: _K) -> Optional[_V]: - ... - - @overload - def get(self, key: _K, default: _T) -> Union[_V, _T]: - ... - - # We need to override this explicitly, because our defaultdict-like behavior - # will make the default implementation (from our base class) always insert - # the key. - def get(self, key, default=None): - if key in self: - return self[key] - else: - return default - - def __contains__(self, item: _K) -> bool: - item = self._key_checker.CheckValue(item) - return item in self._values - - def __setitem__(self, key: _K, value: _V) -> NoReturn: - raise ValueError('May not set values directly, call my_map[key].foo = 5') - - def __delitem__(self, key: _K) -> None: - key = self._key_checker.CheckValue(key) - del self._values[key] - self._message_listener.Modified() - - def __len__(self) -> int: - return len(self._values) - - def __iter__(self) -> Iterator[_K]: - return iter(self._values) - - def __repr__(self) -> str: - return repr(self._values) - - def MergeFrom(self, other: 'MessageMap[_K, _V]') -> None: - # pylint: disable=protected-access - for key in other._values: - # According to documentation: "When parsing from the wire or when merging, - # if there are duplicate map keys the last key seen is used". - if key in self: - del self[key] - self[key].CopyFrom(other[key]) - # self._message_listener.Modified() not required here, because - # mutations to submessages already propagate. - - def InvalidateIterators(self) -> None: - # It appears that the only way to reliably invalidate iterators to - # self._values is to ensure that its size changes. - original = self._values - self._values = original.copy() - original[None] = None - - # This is defined in the abstract base, but we can do it much more cheaply. - def clear(self) -> None: - self._values.clear() - self._message_listener.Modified() - - def GetEntryClass(self) -> Any: - return self._entry_descriptor._concrete_class - - -class _UnknownField: - """A parsed unknown field.""" - - # Disallows assignment to other attributes. - __slots__ = ['_field_number', '_wire_type', '_data'] - - def __init__(self, field_number, wire_type, data): - self._field_number = field_number - self._wire_type = wire_type - self._data = data - return - - def __lt__(self, other): - # pylint: disable=protected-access - return self._field_number < other._field_number - - def __eq__(self, other): - if self is other: - return True - # pylint: disable=protected-access - return (self._field_number == other._field_number and - self._wire_type == other._wire_type and - self._data == other._data) - - -class UnknownFieldRef: # pylint: disable=missing-class-docstring - - def __init__(self, parent, index): - self._parent = parent - self._index = index - - def _check_valid(self): - if not self._parent: - raise ValueError('UnknownField does not exist. ' - 'The parent message might be cleared.') - if self._index >= len(self._parent): - raise ValueError('UnknownField does not exist. ' - 'The parent message might be cleared.') - - @property - def field_number(self): - self._check_valid() - # pylint: disable=protected-access - return self._parent._internal_get(self._index)._field_number - - @property - def wire_type(self): - self._check_valid() - # pylint: disable=protected-access - return self._parent._internal_get(self._index)._wire_type - - @property - def data(self): - self._check_valid() - # pylint: disable=protected-access - return self._parent._internal_get(self._index)._data - - -class UnknownFieldSet: - """UnknownField container""" - - # Disallows assignment to other attributes. - __slots__ = ['_values'] - - def __init__(self): - self._values = [] - - def __getitem__(self, index): - if self._values is None: - raise ValueError('UnknownFields does not exist. ' - 'The parent message might be cleared.') - size = len(self._values) - if index < 0: - index += size - if index < 0 or index >= size: - raise IndexError('index %d out of range'.index) - - return UnknownFieldRef(self, index) - - def _internal_get(self, index): - return self._values[index] - - def __len__(self): - if self._values is None: - raise ValueError('UnknownFields does not exist. ' - 'The parent message might be cleared.') - return len(self._values) - - def _add(self, field_number, wire_type, data): - unknown_field = _UnknownField(field_number, wire_type, data) - self._values.append(unknown_field) - return unknown_field - - def __iter__(self): - for i in range(len(self)): - yield UnknownFieldRef(self, i) - - def _extend(self, other): - if other is None: - return - # pylint: disable=protected-access - self._values.extend(other._values) - - def __eq__(self, other): - if self is other: - return True - # Sort unknown fields because their order shouldn't - # affect equality test. - values = list(self._values) - if other is None: - return not values - values.sort() - # pylint: disable=protected-access - other_values = sorted(other._values) - return values == other_values - - def _clear(self): - for value in self._values: - # pylint: disable=protected-access - if isinstance(value._data, UnknownFieldSet): - value._data._clear() # pylint: disable=protected-access - self._values = None diff --git a/scripts/protobuf3/protobuf3/internal/decoder.py b/scripts/protobuf3/protobuf3/internal/decoder.py deleted file mode 100644 index bc1b7b7..0000000 --- a/scripts/protobuf3/protobuf3/internal/decoder.py +++ /dev/null @@ -1,1029 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Code for decoding protocol buffer primitives. - -This code is very similar to encoder.py -- read the docs for that module first. - -A "decoder" is a function with the signature: - Decode(buffer, pos, end, message, field_dict) -The arguments are: - buffer: The string containing the encoded message. - pos: The current position in the string. - end: The position in the string where the current message ends. May be - less than len(buffer) if we're reading a sub-message. - message: The message object into which we're parsing. - field_dict: message._fields (avoids a hashtable lookup). -The decoder reads the field and stores it into field_dict, returning the new -buffer position. A decoder for a repeated field may proactively decode all of -the elements of that field, if they appear consecutively. - -Note that decoders may throw any of the following: - IndexError: Indicates a truncated message. - struct.error: Unpacking of a fixed-width field failed. - message.DecodeError: Other errors. - -Decoders are expected to raise an exception if they are called with pos > end. -This allows callers to be lax about bounds checking: it's fineto read past -"end" as long as you are sure that someone else will notice and throw an -exception later on. - -Something up the call stack is expected to catch IndexError and struct.error -and convert them to message.DecodeError. - -Decoders are constructed using decoder constructors with the signature: - MakeDecoder(field_number, is_repeated, is_packed, key, new_default) -The arguments are: - field_number: The field number of the field we want to decode. - is_repeated: Is the field a repeated field? (bool) - is_packed: Is the field a packed field? (bool) - key: The key to use when looking up the field within field_dict. - (This is actually the FieldDescriptor but nothing in this - file should depend on that.) - new_default: A function which takes a message object as a parameter and - returns a new instance of the default value for this field. - (This is called for repeated fields and sub-messages, when an - instance does not already exist.) - -As with encoders, we define a decoder constructor for every type of field. -Then, for every field of every message class we construct an actual decoder. -That decoder goes into a dict indexed by tag, so when we decode a message -we repeatedly read a tag, look up the corresponding decoder, and invoke it. -""" - -__author__ = 'kenton@google.com (Kenton Varda)' - -import math -import struct - -from google.protobuf.internal import containers -from google.protobuf.internal import encoder -from google.protobuf.internal import wire_format -from google.protobuf import message - - -# This is not for optimization, but rather to avoid conflicts with local -# variables named "message". -_DecodeError = message.DecodeError - - -def _VarintDecoder(mask, result_type): - """Return an encoder for a basic varint value (does not include tag). - - Decoded values will be bitwise-anded with the given mask before being - returned, e.g. to limit them to 32 bits. The returned decoder does not - take the usual "end" parameter -- the caller is expected to do bounds checking - after the fact (often the caller can defer such checking until later). The - decoder returns a (value, new_pos) pair. - """ - - def DecodeVarint(buffer, pos): - result = 0 - shift = 0 - while 1: - b = buffer[pos] - result |= ((b & 0x7f) << shift) - pos += 1 - if not (b & 0x80): - result &= mask - result = result_type(result) - return (result, pos) - shift += 7 - if shift >= 64: - raise _DecodeError('Too many bytes when decoding varint.') - return DecodeVarint - - -def _SignedVarintDecoder(bits, result_type): - """Like _VarintDecoder() but decodes signed values.""" - - signbit = 1 << (bits - 1) - mask = (1 << bits) - 1 - - def DecodeVarint(buffer, pos): - result = 0 - shift = 0 - while 1: - b = buffer[pos] - result |= ((b & 0x7f) << shift) - pos += 1 - if not (b & 0x80): - result &= mask - result = (result ^ signbit) - signbit - result = result_type(result) - return (result, pos) - shift += 7 - if shift >= 64: - raise _DecodeError('Too many bytes when decoding varint.') - return DecodeVarint - -# All 32-bit and 64-bit values are represented as int. -_DecodeVarint = _VarintDecoder((1 << 64) - 1, int) -_DecodeSignedVarint = _SignedVarintDecoder(64, int) - -# Use these versions for values which must be limited to 32 bits. -_DecodeVarint32 = _VarintDecoder((1 << 32) - 1, int) -_DecodeSignedVarint32 = _SignedVarintDecoder(32, int) - - -def ReadTag(buffer, pos): - """Read a tag from the memoryview, and return a (tag_bytes, new_pos) tuple. - - We return the raw bytes of the tag rather than decoding them. The raw - bytes can then be used to look up the proper decoder. This effectively allows - us to trade some work that would be done in pure-python (decoding a varint) - for work that is done in C (searching for a byte string in a hash table). - In a low-level language it would be much cheaper to decode the varint and - use that, but not in Python. - - Args: - buffer: memoryview object of the encoded bytes - pos: int of the current position to start from - - Returns: - Tuple[bytes, int] of the tag data and new position. - """ - start = pos - while buffer[pos] & 0x80: - pos += 1 - pos += 1 - - tag_bytes = buffer[start:pos].tobytes() - return tag_bytes, pos - - -# -------------------------------------------------------------------- - - -def _SimpleDecoder(wire_type, decode_value): - """Return a constructor for a decoder for fields of a particular type. - - Args: - wire_type: The field's wire type. - decode_value: A function which decodes an individual value, e.g. - _DecodeVarint() - """ - - def SpecificDecoder(field_number, is_repeated, is_packed, key, new_default, - clear_if_default=False): - if is_packed: - local_DecodeVarint = _DecodeVarint - def DecodePackedField(buffer, pos, end, message, field_dict): - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - (endpoint, pos) = local_DecodeVarint(buffer, pos) - endpoint += pos - if endpoint > end: - raise _DecodeError('Truncated message.') - while pos < endpoint: - (element, pos) = decode_value(buffer, pos) - value.append(element) - if pos > endpoint: - del value[-1] # Discard corrupt value. - raise _DecodeError('Packed element was truncated.') - return pos - return DecodePackedField - elif is_repeated: - tag_bytes = encoder.TagBytes(field_number, wire_type) - tag_len = len(tag_bytes) - def DecodeRepeatedField(buffer, pos, end, message, field_dict): - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - while 1: - (element, new_pos) = decode_value(buffer, pos) - value.append(element) - # Predict that the next tag is another copy of the same repeated - # field. - pos = new_pos + tag_len - if buffer[new_pos:pos] != tag_bytes or new_pos >= end: - # Prediction failed. Return. - if new_pos > end: - raise _DecodeError('Truncated message.') - return new_pos - return DecodeRepeatedField - else: - def DecodeField(buffer, pos, end, message, field_dict): - (new_value, pos) = decode_value(buffer, pos) - if pos > end: - raise _DecodeError('Truncated message.') - if clear_if_default and not new_value: - field_dict.pop(key, None) - else: - field_dict[key] = new_value - return pos - return DecodeField - - return SpecificDecoder - - -def _ModifiedDecoder(wire_type, decode_value, modify_value): - """Like SimpleDecoder but additionally invokes modify_value on every value - before storing it. Usually modify_value is ZigZagDecode. - """ - - # Reusing _SimpleDecoder is slightly slower than copying a bunch of code, but - # not enough to make a significant difference. - - def InnerDecode(buffer, pos): - (result, new_pos) = decode_value(buffer, pos) - return (modify_value(result), new_pos) - return _SimpleDecoder(wire_type, InnerDecode) - - -def _StructPackDecoder(wire_type, format): - """Return a constructor for a decoder for a fixed-width field. - - Args: - wire_type: The field's wire type. - format: The format string to pass to struct.unpack(). - """ - - value_size = struct.calcsize(format) - local_unpack = struct.unpack - - # Reusing _SimpleDecoder is slightly slower than copying a bunch of code, but - # not enough to make a significant difference. - - # Note that we expect someone up-stack to catch struct.error and convert - # it to _DecodeError -- this way we don't have to set up exception- - # handling blocks every time we parse one value. - - def InnerDecode(buffer, pos): - new_pos = pos + value_size - result = local_unpack(format, buffer[pos:new_pos])[0] - return (result, new_pos) - return _SimpleDecoder(wire_type, InnerDecode) - - -def _FloatDecoder(): - """Returns a decoder for a float field. - - This code works around a bug in struct.unpack for non-finite 32-bit - floating-point values. - """ - - local_unpack = struct.unpack - - def InnerDecode(buffer, pos): - """Decode serialized float to a float and new position. - - Args: - buffer: memoryview of the serialized bytes - pos: int, position in the memory view to start at. - - Returns: - Tuple[float, int] of the deserialized float value and new position - in the serialized data. - """ - # We expect a 32-bit value in little-endian byte order. Bit 1 is the sign - # bit, bits 2-9 represent the exponent, and bits 10-32 are the significand. - new_pos = pos + 4 - float_bytes = buffer[pos:new_pos].tobytes() - - # If this value has all its exponent bits set, then it's non-finite. - # In Python 2.4, struct.unpack will convert it to a finite 64-bit value. - # To avoid that, we parse it specially. - if (float_bytes[3:4] in b'\x7F\xFF' and float_bytes[2:3] >= b'\x80'): - # If at least one significand bit is set... - if float_bytes[0:3] != b'\x00\x00\x80': - return (math.nan, new_pos) - # If sign bit is set... - if float_bytes[3:4] == b'\xFF': - return (-math.inf, new_pos) - return (math.inf, new_pos) - - # Note that we expect someone up-stack to catch struct.error and convert - # it to _DecodeError -- this way we don't have to set up exception- - # handling blocks every time we parse one value. - result = local_unpack('= b'\xF0') - and (double_bytes[0:7] != b'\x00\x00\x00\x00\x00\x00\xF0')): - return (math.nan, new_pos) - - # Note that we expect someone up-stack to catch struct.error and convert - # it to _DecodeError -- this way we don't have to set up exception- - # handling blocks every time we parse one value. - result = local_unpack(' end: - raise _DecodeError('Truncated message.') - while pos < endpoint: - value_start_pos = pos - (element, pos) = _DecodeSignedVarint32(buffer, pos) - # pylint: disable=protected-access - if element in enum_type.values_by_number: - value.append(element) - else: - if not message._unknown_fields: - message._unknown_fields = [] - tag_bytes = encoder.TagBytes(field_number, - wire_format.WIRETYPE_VARINT) - - message._unknown_fields.append( - (tag_bytes, buffer[value_start_pos:pos].tobytes())) - if message._unknown_field_set is None: - message._unknown_field_set = containers.UnknownFieldSet() - message._unknown_field_set._add( - field_number, wire_format.WIRETYPE_VARINT, element) - # pylint: enable=protected-access - if pos > endpoint: - if element in enum_type.values_by_number: - del value[-1] # Discard corrupt value. - else: - del message._unknown_fields[-1] - # pylint: disable=protected-access - del message._unknown_field_set._values[-1] - # pylint: enable=protected-access - raise _DecodeError('Packed element was truncated.') - return pos - return DecodePackedField - elif is_repeated: - tag_bytes = encoder.TagBytes(field_number, wire_format.WIRETYPE_VARINT) - tag_len = len(tag_bytes) - def DecodeRepeatedField(buffer, pos, end, message, field_dict): - """Decode serialized repeated enum to its value and a new position. - - Args: - buffer: memoryview of the serialized bytes. - pos: int, position in the memory view to start at. - end: int, end position of serialized data - message: Message object to store unknown fields in - field_dict: Map[Descriptor, Any] to store decoded values in. - - Returns: - int, new position in serialized data. - """ - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - while 1: - (element, new_pos) = _DecodeSignedVarint32(buffer, pos) - # pylint: disable=protected-access - if element in enum_type.values_by_number: - value.append(element) - else: - if not message._unknown_fields: - message._unknown_fields = [] - message._unknown_fields.append( - (tag_bytes, buffer[pos:new_pos].tobytes())) - if message._unknown_field_set is None: - message._unknown_field_set = containers.UnknownFieldSet() - message._unknown_field_set._add( - field_number, wire_format.WIRETYPE_VARINT, element) - # pylint: enable=protected-access - # Predict that the next tag is another copy of the same repeated - # field. - pos = new_pos + tag_len - if buffer[new_pos:pos] != tag_bytes or new_pos >= end: - # Prediction failed. Return. - if new_pos > end: - raise _DecodeError('Truncated message.') - return new_pos - return DecodeRepeatedField - else: - def DecodeField(buffer, pos, end, message, field_dict): - """Decode serialized repeated enum to its value and a new position. - - Args: - buffer: memoryview of the serialized bytes. - pos: int, position in the memory view to start at. - end: int, end position of serialized data - message: Message object to store unknown fields in - field_dict: Map[Descriptor, Any] to store decoded values in. - - Returns: - int, new position in serialized data. - """ - value_start_pos = pos - (enum_value, pos) = _DecodeSignedVarint32(buffer, pos) - if pos > end: - raise _DecodeError('Truncated message.') - if clear_if_default and not enum_value: - field_dict.pop(key, None) - return pos - # pylint: disable=protected-access - if enum_value in enum_type.values_by_number: - field_dict[key] = enum_value - else: - if not message._unknown_fields: - message._unknown_fields = [] - tag_bytes = encoder.TagBytes(field_number, - wire_format.WIRETYPE_VARINT) - message._unknown_fields.append( - (tag_bytes, buffer[value_start_pos:pos].tobytes())) - if message._unknown_field_set is None: - message._unknown_field_set = containers.UnknownFieldSet() - message._unknown_field_set._add( - field_number, wire_format.WIRETYPE_VARINT, enum_value) - # pylint: enable=protected-access - return pos - return DecodeField - - -# -------------------------------------------------------------------- - - -Int32Decoder = _SimpleDecoder( - wire_format.WIRETYPE_VARINT, _DecodeSignedVarint32) - -Int64Decoder = _SimpleDecoder( - wire_format.WIRETYPE_VARINT, _DecodeSignedVarint) - -UInt32Decoder = _SimpleDecoder(wire_format.WIRETYPE_VARINT, _DecodeVarint32) -UInt64Decoder = _SimpleDecoder(wire_format.WIRETYPE_VARINT, _DecodeVarint) - -SInt32Decoder = _ModifiedDecoder( - wire_format.WIRETYPE_VARINT, _DecodeVarint32, wire_format.ZigZagDecode) -SInt64Decoder = _ModifiedDecoder( - wire_format.WIRETYPE_VARINT, _DecodeVarint, wire_format.ZigZagDecode) - -# Note that Python conveniently guarantees that when using the '<' prefix on -# formats, they will also have the same size across all platforms (as opposed -# to without the prefix, where their sizes depend on the C compiler's basic -# type sizes). -Fixed32Decoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED32, ' end: - raise _DecodeError('Truncated string.') - value.append(_ConvertToUnicode(buffer[pos:new_pos])) - # Predict that the next tag is another copy of the same repeated field. - pos = new_pos + tag_len - if buffer[new_pos:pos] != tag_bytes or new_pos == end: - # Prediction failed. Return. - return new_pos - return DecodeRepeatedField - else: - def DecodeField(buffer, pos, end, message, field_dict): - (size, pos) = local_DecodeVarint(buffer, pos) - new_pos = pos + size - if new_pos > end: - raise _DecodeError('Truncated string.') - if clear_if_default and not size: - field_dict.pop(key, None) - else: - field_dict[key] = _ConvertToUnicode(buffer[pos:new_pos]) - return new_pos - return DecodeField - - -def BytesDecoder(field_number, is_repeated, is_packed, key, new_default, - clear_if_default=False): - """Returns a decoder for a bytes field.""" - - local_DecodeVarint = _DecodeVarint - - assert not is_packed - if is_repeated: - tag_bytes = encoder.TagBytes(field_number, - wire_format.WIRETYPE_LENGTH_DELIMITED) - tag_len = len(tag_bytes) - def DecodeRepeatedField(buffer, pos, end, message, field_dict): - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - while 1: - (size, pos) = local_DecodeVarint(buffer, pos) - new_pos = pos + size - if new_pos > end: - raise _DecodeError('Truncated string.') - value.append(buffer[pos:new_pos].tobytes()) - # Predict that the next tag is another copy of the same repeated field. - pos = new_pos + tag_len - if buffer[new_pos:pos] != tag_bytes or new_pos == end: - # Prediction failed. Return. - return new_pos - return DecodeRepeatedField - else: - def DecodeField(buffer, pos, end, message, field_dict): - (size, pos) = local_DecodeVarint(buffer, pos) - new_pos = pos + size - if new_pos > end: - raise _DecodeError('Truncated string.') - if clear_if_default and not size: - field_dict.pop(key, None) - else: - field_dict[key] = buffer[pos:new_pos].tobytes() - return new_pos - return DecodeField - - -def GroupDecoder(field_number, is_repeated, is_packed, key, new_default): - """Returns a decoder for a group field.""" - - end_tag_bytes = encoder.TagBytes(field_number, - wire_format.WIRETYPE_END_GROUP) - end_tag_len = len(end_tag_bytes) - - assert not is_packed - if is_repeated: - tag_bytes = encoder.TagBytes(field_number, - wire_format.WIRETYPE_START_GROUP) - tag_len = len(tag_bytes) - def DecodeRepeatedField(buffer, pos, end, message, field_dict): - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - while 1: - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - # Read sub-message. - pos = value.add()._InternalParse(buffer, pos, end) - # Read end tag. - new_pos = pos+end_tag_len - if buffer[pos:new_pos] != end_tag_bytes or new_pos > end: - raise _DecodeError('Missing group end tag.') - # Predict that the next tag is another copy of the same repeated field. - pos = new_pos + tag_len - if buffer[new_pos:pos] != tag_bytes or new_pos == end: - # Prediction failed. Return. - return new_pos - return DecodeRepeatedField - else: - def DecodeField(buffer, pos, end, message, field_dict): - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - # Read sub-message. - pos = value._InternalParse(buffer, pos, end) - # Read end tag. - new_pos = pos+end_tag_len - if buffer[pos:new_pos] != end_tag_bytes or new_pos > end: - raise _DecodeError('Missing group end tag.') - return new_pos - return DecodeField - - -def MessageDecoder(field_number, is_repeated, is_packed, key, new_default): - """Returns a decoder for a message field.""" - - local_DecodeVarint = _DecodeVarint - - assert not is_packed - if is_repeated: - tag_bytes = encoder.TagBytes(field_number, - wire_format.WIRETYPE_LENGTH_DELIMITED) - tag_len = len(tag_bytes) - def DecodeRepeatedField(buffer, pos, end, message, field_dict): - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - while 1: - # Read length. - (size, pos) = local_DecodeVarint(buffer, pos) - new_pos = pos + size - if new_pos > end: - raise _DecodeError('Truncated message.') - # Read sub-message. - if value.add()._InternalParse(buffer, pos, new_pos) != new_pos: - # The only reason _InternalParse would return early is if it - # encountered an end-group tag. - raise _DecodeError('Unexpected end-group tag.') - # Predict that the next tag is another copy of the same repeated field. - pos = new_pos + tag_len - if buffer[new_pos:pos] != tag_bytes or new_pos == end: - # Prediction failed. Return. - return new_pos - return DecodeRepeatedField - else: - def DecodeField(buffer, pos, end, message, field_dict): - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - # Read length. - (size, pos) = local_DecodeVarint(buffer, pos) - new_pos = pos + size - if new_pos > end: - raise _DecodeError('Truncated message.') - # Read sub-message. - if value._InternalParse(buffer, pos, new_pos) != new_pos: - # The only reason _InternalParse would return early is if it encountered - # an end-group tag. - raise _DecodeError('Unexpected end-group tag.') - return new_pos - return DecodeField - - -# -------------------------------------------------------------------- - -MESSAGE_SET_ITEM_TAG = encoder.TagBytes(1, wire_format.WIRETYPE_START_GROUP) - -def MessageSetItemDecoder(descriptor): - """Returns a decoder for a MessageSet item. - - The parameter is the message Descriptor. - - The message set message looks like this: - message MessageSet { - repeated group Item = 1 { - required int32 type_id = 2; - required string message = 3; - } - } - """ - - type_id_tag_bytes = encoder.TagBytes(2, wire_format.WIRETYPE_VARINT) - message_tag_bytes = encoder.TagBytes(3, wire_format.WIRETYPE_LENGTH_DELIMITED) - item_end_tag_bytes = encoder.TagBytes(1, wire_format.WIRETYPE_END_GROUP) - - local_ReadTag = ReadTag - local_DecodeVarint = _DecodeVarint - local_SkipField = SkipField - - def DecodeItem(buffer, pos, end, message, field_dict): - """Decode serialized message set to its value and new position. - - Args: - buffer: memoryview of the serialized bytes. - pos: int, position in the memory view to start at. - end: int, end position of serialized data - message: Message object to store unknown fields in - field_dict: Map[Descriptor, Any] to store decoded values in. - - Returns: - int, new position in serialized data. - """ - message_set_item_start = pos - type_id = -1 - message_start = -1 - message_end = -1 - - # Technically, type_id and message can appear in any order, so we need - # a little loop here. - while 1: - (tag_bytes, pos) = local_ReadTag(buffer, pos) - if tag_bytes == type_id_tag_bytes: - (type_id, pos) = local_DecodeVarint(buffer, pos) - elif tag_bytes == message_tag_bytes: - (size, message_start) = local_DecodeVarint(buffer, pos) - pos = message_end = message_start + size - elif tag_bytes == item_end_tag_bytes: - break - else: - pos = SkipField(buffer, pos, end, tag_bytes) - if pos == -1: - raise _DecodeError('Missing group end tag.') - - if pos > end: - raise _DecodeError('Truncated message.') - - if type_id == -1: - raise _DecodeError('MessageSet item missing type_id.') - if message_start == -1: - raise _DecodeError('MessageSet item missing message.') - - extension = message.Extensions._FindExtensionByNumber(type_id) - # pylint: disable=protected-access - if extension is not None: - value = field_dict.get(extension) - if value is None: - message_type = extension.message_type - if not hasattr(message_type, '_concrete_class'): - # pylint: disable=protected-access - message._FACTORY.GetPrototype(message_type) - value = field_dict.setdefault( - extension, message_type._concrete_class()) - if value._InternalParse(buffer, message_start,message_end) != message_end: - # The only reason _InternalParse would return early is if it encountered - # an end-group tag. - raise _DecodeError('Unexpected end-group tag.') - else: - if not message._unknown_fields: - message._unknown_fields = [] - message._unknown_fields.append( - (MESSAGE_SET_ITEM_TAG, buffer[message_set_item_start:pos].tobytes())) - if message._unknown_field_set is None: - message._unknown_field_set = containers.UnknownFieldSet() - message._unknown_field_set._add( - type_id, - wire_format.WIRETYPE_LENGTH_DELIMITED, - buffer[message_start:message_end].tobytes()) - # pylint: enable=protected-access - - return pos - - return DecodeItem - -# -------------------------------------------------------------------- - -def MapDecoder(field_descriptor, new_default, is_message_map): - """Returns a decoder for a map field.""" - - key = field_descriptor - tag_bytes = encoder.TagBytes(field_descriptor.number, - wire_format.WIRETYPE_LENGTH_DELIMITED) - tag_len = len(tag_bytes) - local_DecodeVarint = _DecodeVarint - # Can't read _concrete_class yet; might not be initialized. - message_type = field_descriptor.message_type - - def DecodeMap(buffer, pos, end, message, field_dict): - submsg = message_type._concrete_class() - value = field_dict.get(key) - if value is None: - value = field_dict.setdefault(key, new_default(message)) - while 1: - # Read length. - (size, pos) = local_DecodeVarint(buffer, pos) - new_pos = pos + size - if new_pos > end: - raise _DecodeError('Truncated message.') - # Read sub-message. - submsg.Clear() - if submsg._InternalParse(buffer, pos, new_pos) != new_pos: - # The only reason _InternalParse would return early is if it - # encountered an end-group tag. - raise _DecodeError('Unexpected end-group tag.') - - if is_message_map: - value[submsg.key].CopyFrom(submsg.value) - else: - value[submsg.key] = submsg.value - - # Predict that the next tag is another copy of the same repeated field. - pos = new_pos + tag_len - if buffer[new_pos:pos] != tag_bytes or new_pos == end: - # Prediction failed. Return. - return new_pos - - return DecodeMap - -# -------------------------------------------------------------------- -# Optimization is not as heavy here because calls to SkipField() are rare, -# except for handling end-group tags. - -def _SkipVarint(buffer, pos, end): - """Skip a varint value. Returns the new position.""" - # Previously ord(buffer[pos]) raised IndexError when pos is out of range. - # With this code, ord(b'') raises TypeError. Both are handled in - # python_message.py to generate a 'Truncated message' error. - while ord(buffer[pos:pos+1].tobytes()) & 0x80: - pos += 1 - pos += 1 - if pos > end: - raise _DecodeError('Truncated message.') - return pos - -def _SkipFixed64(buffer, pos, end): - """Skip a fixed64 value. Returns the new position.""" - - pos += 8 - if pos > end: - raise _DecodeError('Truncated message.') - return pos - - -def _DecodeFixed64(buffer, pos): - """Decode a fixed64.""" - new_pos = pos + 8 - return (struct.unpack(' end: - raise _DecodeError('Truncated message.') - return pos - - -def _SkipGroup(buffer, pos, end): - """Skip sub-group. Returns the new position.""" - - while 1: - (tag_bytes, pos) = ReadTag(buffer, pos) - new_pos = SkipField(buffer, pos, end, tag_bytes) - if new_pos == -1: - return pos - pos = new_pos - - -def _DecodeUnknownFieldSet(buffer, pos, end_pos=None): - """Decode UnknownFieldSet. Returns the UnknownFieldSet and new position.""" - - unknown_field_set = containers.UnknownFieldSet() - while end_pos is None or pos < end_pos: - (tag_bytes, pos) = ReadTag(buffer, pos) - (tag, _) = _DecodeVarint(tag_bytes, 0) - field_number, wire_type = wire_format.UnpackTag(tag) - if wire_type == wire_format.WIRETYPE_END_GROUP: - break - (data, pos) = _DecodeUnknownField(buffer, pos, wire_type) - # pylint: disable=protected-access - unknown_field_set._add(field_number, wire_type, data) - - return (unknown_field_set, pos) - - -def _DecodeUnknownField(buffer, pos, wire_type): - """Decode a unknown field. Returns the UnknownField and new position.""" - - if wire_type == wire_format.WIRETYPE_VARINT: - (data, pos) = _DecodeVarint(buffer, pos) - elif wire_type == wire_format.WIRETYPE_FIXED64: - (data, pos) = _DecodeFixed64(buffer, pos) - elif wire_type == wire_format.WIRETYPE_FIXED32: - (data, pos) = _DecodeFixed32(buffer, pos) - elif wire_type == wire_format.WIRETYPE_LENGTH_DELIMITED: - (size, pos) = _DecodeVarint(buffer, pos) - data = buffer[pos:pos+size].tobytes() - pos += size - elif wire_type == wire_format.WIRETYPE_START_GROUP: - (data, pos) = _DecodeUnknownFieldSet(buffer, pos) - elif wire_type == wire_format.WIRETYPE_END_GROUP: - return (0, -1) - else: - raise _DecodeError('Wrong wire type in tag.') - - return (data, pos) - - -def _EndGroup(buffer, pos, end): - """Skipping an END_GROUP tag returns -1 to tell the parent loop to break.""" - - return -1 - - -def _SkipFixed32(buffer, pos, end): - """Skip a fixed32 value. Returns the new position.""" - - pos += 4 - if pos > end: - raise _DecodeError('Truncated message.') - return pos - - -def _DecodeFixed32(buffer, pos): - """Decode a fixed32.""" - - new_pos = pos + 4 - return (struct.unpack('B').pack - - def EncodeVarint(write, value, unused_deterministic=None): - bits = value & 0x7f - value >>= 7 - while value: - write(local_int2byte(0x80|bits)) - bits = value & 0x7f - value >>= 7 - return write(local_int2byte(bits)) - - return EncodeVarint - - -def _SignedVarintEncoder(): - """Return an encoder for a basic signed varint value (does not include - tag).""" - - local_int2byte = struct.Struct('>B').pack - - def EncodeSignedVarint(write, value, unused_deterministic=None): - if value < 0: - value += (1 << 64) - bits = value & 0x7f - value >>= 7 - while value: - write(local_int2byte(0x80|bits)) - bits = value & 0x7f - value >>= 7 - return write(local_int2byte(bits)) - - return EncodeSignedVarint - - -_EncodeVarint = _VarintEncoder() -_EncodeSignedVarint = _SignedVarintEncoder() - - -def _VarintBytes(value): - """Encode the given integer as a varint and return the bytes. This is only - called at startup time so it doesn't need to be fast.""" - - pieces = [] - _EncodeVarint(pieces.append, value, True) - return b"".join(pieces) - - -def TagBytes(field_number, wire_type): - """Encode the given tag and return the bytes. Only called at startup.""" - - return bytes(_VarintBytes(wire_format.PackTag(field_number, wire_type))) - -# -------------------------------------------------------------------- -# As with sizers (see above), we have a number of common encoder -# implementations. - - -def _SimpleEncoder(wire_type, encode_value, compute_value_size): - """Return a constructor for an encoder for fields of a particular type. - - Args: - wire_type: The field's wire type, for encoding tags. - encode_value: A function which encodes an individual value, e.g. - _EncodeVarint(). - compute_value_size: A function which computes the size of an individual - value, e.g. _VarintSize(). - """ - - def SpecificEncoder(field_number, is_repeated, is_packed): - if is_packed: - tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) - local_EncodeVarint = _EncodeVarint - def EncodePackedField(write, value, deterministic): - write(tag_bytes) - size = 0 - for element in value: - size += compute_value_size(element) - local_EncodeVarint(write, size, deterministic) - for element in value: - encode_value(write, element, deterministic) - return EncodePackedField - elif is_repeated: - tag_bytes = TagBytes(field_number, wire_type) - def EncodeRepeatedField(write, value, deterministic): - for element in value: - write(tag_bytes) - encode_value(write, element, deterministic) - return EncodeRepeatedField - else: - tag_bytes = TagBytes(field_number, wire_type) - def EncodeField(write, value, deterministic): - write(tag_bytes) - return encode_value(write, value, deterministic) - return EncodeField - - return SpecificEncoder - - -def _ModifiedEncoder(wire_type, encode_value, compute_value_size, modify_value): - """Like SimpleEncoder but additionally invokes modify_value on every value - before passing it to encode_value. Usually modify_value is ZigZagEncode.""" - - def SpecificEncoder(field_number, is_repeated, is_packed): - if is_packed: - tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) - local_EncodeVarint = _EncodeVarint - def EncodePackedField(write, value, deterministic): - write(tag_bytes) - size = 0 - for element in value: - size += compute_value_size(modify_value(element)) - local_EncodeVarint(write, size, deterministic) - for element in value: - encode_value(write, modify_value(element), deterministic) - return EncodePackedField - elif is_repeated: - tag_bytes = TagBytes(field_number, wire_type) - def EncodeRepeatedField(write, value, deterministic): - for element in value: - write(tag_bytes) - encode_value(write, modify_value(element), deterministic) - return EncodeRepeatedField - else: - tag_bytes = TagBytes(field_number, wire_type) - def EncodeField(write, value, deterministic): - write(tag_bytes) - return encode_value(write, modify_value(value), deterministic) - return EncodeField - - return SpecificEncoder - - -def _StructPackEncoder(wire_type, format): - """Return a constructor for an encoder for a fixed-width field. - - Args: - wire_type: The field's wire type, for encoding tags. - format: The format string to pass to struct.pack(). - """ - - value_size = struct.calcsize(format) - - def SpecificEncoder(field_number, is_repeated, is_packed): - local_struct_pack = struct.pack - if is_packed: - tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) - local_EncodeVarint = _EncodeVarint - def EncodePackedField(write, value, deterministic): - write(tag_bytes) - local_EncodeVarint(write, len(value) * value_size, deterministic) - for element in value: - write(local_struct_pack(format, element)) - return EncodePackedField - elif is_repeated: - tag_bytes = TagBytes(field_number, wire_type) - def EncodeRepeatedField(write, value, unused_deterministic=None): - for element in value: - write(tag_bytes) - write(local_struct_pack(format, element)) - return EncodeRepeatedField - else: - tag_bytes = TagBytes(field_number, wire_type) - def EncodeField(write, value, unused_deterministic=None): - write(tag_bytes) - return write(local_struct_pack(format, value)) - return EncodeField - - return SpecificEncoder - - -def _FloatingPointEncoder(wire_type, format): - """Return a constructor for an encoder for float fields. - - This is like StructPackEncoder, but catches errors that may be due to - passing non-finite floating-point values to struct.pack, and makes a - second attempt to encode those values. - - Args: - wire_type: The field's wire type, for encoding tags. - format: The format string to pass to struct.pack(). - """ - - value_size = struct.calcsize(format) - if value_size == 4: - def EncodeNonFiniteOrRaise(write, value): - # Remember that the serialized form uses little-endian byte order. - if value == _POS_INF: - write(b'\x00\x00\x80\x7F') - elif value == _NEG_INF: - write(b'\x00\x00\x80\xFF') - elif value != value: # NaN - write(b'\x00\x00\xC0\x7F') - else: - raise - elif value_size == 8: - def EncodeNonFiniteOrRaise(write, value): - if value == _POS_INF: - write(b'\x00\x00\x00\x00\x00\x00\xF0\x7F') - elif value == _NEG_INF: - write(b'\x00\x00\x00\x00\x00\x00\xF0\xFF') - elif value != value: # NaN - write(b'\x00\x00\x00\x00\x00\x00\xF8\x7F') - else: - raise - else: - raise ValueError('Can\'t encode floating-point values that are ' - '%d bytes long (only 4 or 8)' % value_size) - - def SpecificEncoder(field_number, is_repeated, is_packed): - local_struct_pack = struct.pack - if is_packed: - tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) - local_EncodeVarint = _EncodeVarint - def EncodePackedField(write, value, deterministic): - write(tag_bytes) - local_EncodeVarint(write, len(value) * value_size, deterministic) - for element in value: - # This try/except block is going to be faster than any code that - # we could write to check whether element is finite. - try: - write(local_struct_pack(format, element)) - except SystemError: - EncodeNonFiniteOrRaise(write, element) - return EncodePackedField - elif is_repeated: - tag_bytes = TagBytes(field_number, wire_type) - def EncodeRepeatedField(write, value, unused_deterministic=None): - for element in value: - write(tag_bytes) - try: - write(local_struct_pack(format, element)) - except SystemError: - EncodeNonFiniteOrRaise(write, element) - return EncodeRepeatedField - else: - tag_bytes = TagBytes(field_number, wire_type) - def EncodeField(write, value, unused_deterministic=None): - write(tag_bytes) - try: - write(local_struct_pack(format, value)) - except SystemError: - EncodeNonFiniteOrRaise(write, value) - return EncodeField - - return SpecificEncoder - - -# ==================================================================== -# Here we declare an encoder constructor for each field type. These work -# very similarly to sizer constructors, described earlier. - - -Int32Encoder = Int64Encoder = EnumEncoder = _SimpleEncoder( - wire_format.WIRETYPE_VARINT, _EncodeSignedVarint, _SignedVarintSize) - -UInt32Encoder = UInt64Encoder = _SimpleEncoder( - wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize) - -SInt32Encoder = SInt64Encoder = _ModifiedEncoder( - wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize, - wire_format.ZigZagEncode) - -# Note that Python conveniently guarantees that when using the '<' prefix on -# formats, they will also have the same size across all platforms (as opposed -# to without the prefix, where their sizes depend on the C compiler's basic -# type sizes). -Fixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, ' str - ValueType = int - - def __init__(self, enum_type): - """Inits EnumTypeWrapper with an EnumDescriptor.""" - self._enum_type = enum_type - self.DESCRIPTOR = enum_type # pylint: disable=invalid-name - - def Name(self, number): # pylint: disable=invalid-name - """Returns a string containing the name of an enum value.""" - try: - return self._enum_type.values_by_number[number].name - except KeyError: - pass # fall out to break exception chaining - - if not isinstance(number, int): - raise TypeError( - 'Enum value for {} must be an int, but got {} {!r}.'.format( - self._enum_type.name, type(number), number)) - else: - # repr here to handle the odd case when you pass in a boolean. - raise ValueError('Enum {} has no name defined for value {!r}'.format( - self._enum_type.name, number)) - - def Value(self, name): # pylint: disable=invalid-name - """Returns the value corresponding to the given enum name.""" - try: - return self._enum_type.values_by_name[name].number - except KeyError: - pass # fall out to break exception chaining - raise ValueError('Enum {} has no value defined for name {!r}'.format( - self._enum_type.name, name)) - - def keys(self): - """Return a list of the string names in the enum. - - Returns: - A list of strs, in the order they were defined in the .proto file. - """ - - return [value_descriptor.name - for value_descriptor in self._enum_type.values] - - def values(self): - """Return a list of the integer values in the enum. - - Returns: - A list of ints, in the order they were defined in the .proto file. - """ - - return [value_descriptor.number - for value_descriptor in self._enum_type.values] - - def items(self): - """Return a list of the (name, value) pairs of the enum. - - Returns: - A list of (str, int) pairs, in the order they were defined - in the .proto file. - """ - return [(value_descriptor.name, value_descriptor.number) - for value_descriptor in self._enum_type.values] - - def __getattr__(self, name): - """Returns the value corresponding to the given enum name.""" - try: - return super( - EnumTypeWrapper, - self).__getattribute__('_enum_type').values_by_name[name].number - except KeyError: - pass # fall out to break exception chaining - raise AttributeError('Enum {} has no value defined for name {!r}'.format( - self._enum_type.name, name)) diff --git a/scripts/protobuf3/protobuf3/internal/extension_dict.py b/scripts/protobuf3/protobuf3/internal/extension_dict.py deleted file mode 100644 index b346cf2..0000000 --- a/scripts/protobuf3/protobuf3/internal/extension_dict.py +++ /dev/null @@ -1,213 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Contains _ExtensionDict class to represent extensions. -""" - -from google.protobuf.internal import type_checkers -from google.protobuf.descriptor import FieldDescriptor - - -def _VerifyExtensionHandle(message, extension_handle): - """Verify that the given extension handle is valid.""" - - if not isinstance(extension_handle, FieldDescriptor): - raise KeyError('HasExtension() expects an extension handle, got: %s' % - extension_handle) - - if not extension_handle.is_extension: - raise KeyError('"%s" is not an extension.' % extension_handle.full_name) - - if not extension_handle.containing_type: - raise KeyError('"%s" is missing a containing_type.' - % extension_handle.full_name) - - if extension_handle.containing_type is not message.DESCRIPTOR: - raise KeyError('Extension "%s" extends message type "%s", but this ' - 'message is of type "%s".' % - (extension_handle.full_name, - extension_handle.containing_type.full_name, - message.DESCRIPTOR.full_name)) - - -# TODO(robinson): Unify error handling of "unknown extension" crap. -# TODO(robinson): Support iteritems()-style iteration over all -# extensions with the "has" bits turned on? -class _ExtensionDict(object): - - """Dict-like container for Extension fields on proto instances. - - Note that in all cases we expect extension handles to be - FieldDescriptors. - """ - - def __init__(self, extended_message): - """ - Args: - extended_message: Message instance for which we are the Extensions dict. - """ - self._extended_message = extended_message - - def __getitem__(self, extension_handle): - """Returns the current value of the given extension handle.""" - - _VerifyExtensionHandle(self._extended_message, extension_handle) - - result = self._extended_message._fields.get(extension_handle) - if result is not None: - return result - - if extension_handle.label == FieldDescriptor.LABEL_REPEATED: - result = extension_handle._default_constructor(self._extended_message) - elif extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE: - message_type = extension_handle.message_type - if not hasattr(message_type, '_concrete_class'): - # pylint: disable=protected-access - self._extended_message._FACTORY.GetPrototype(message_type) - assert getattr(extension_handle.message_type, '_concrete_class', None), ( - 'Uninitialized concrete class found for field %r (message type %r)' - % (extension_handle.full_name, - extension_handle.message_type.full_name)) - result = extension_handle.message_type._concrete_class() - try: - result._SetListener(self._extended_message._listener_for_children) - except ReferenceError: - pass - else: - # Singular scalar -- just return the default without inserting into the - # dict. - return extension_handle.default_value - - # Atomically check if another thread has preempted us and, if not, swap - # in the new object we just created. If someone has preempted us, we - # take that object and discard ours. - # WARNING: We are relying on setdefault() being atomic. This is true - # in CPython but we haven't investigated others. This warning appears - # in several other locations in this file. - result = self._extended_message._fields.setdefault( - extension_handle, result) - - return result - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - - my_fields = self._extended_message.ListFields() - other_fields = other._extended_message.ListFields() - - # Get rid of non-extension fields. - my_fields = [field for field in my_fields if field.is_extension] - other_fields = [field for field in other_fields if field.is_extension] - - return my_fields == other_fields - - def __ne__(self, other): - return not self == other - - def __len__(self): - fields = self._extended_message.ListFields() - # Get rid of non-extension fields. - extension_fields = [field for field in fields if field[0].is_extension] - return len(extension_fields) - - def __hash__(self): - raise TypeError('unhashable object') - - # Note that this is only meaningful for non-repeated, scalar extension - # fields. Note also that we may have to call _Modified() when we do - # successfully set a field this way, to set any necessary "has" bits in the - # ancestors of the extended message. - def __setitem__(self, extension_handle, value): - """If extension_handle specifies a non-repeated, scalar extension - field, sets the value of that field. - """ - - _VerifyExtensionHandle(self._extended_message, extension_handle) - - if (extension_handle.label == FieldDescriptor.LABEL_REPEATED or - extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE): - raise TypeError( - 'Cannot assign to extension "%s" because it is a repeated or ' - 'composite type.' % extension_handle.full_name) - - # It's slightly wasteful to lookup the type checker each time, - # but we expect this to be a vanishingly uncommon case anyway. - type_checker = type_checkers.GetTypeChecker(extension_handle) - # pylint: disable=protected-access - self._extended_message._fields[extension_handle] = ( - type_checker.CheckValue(value)) - self._extended_message._Modified() - - def __delitem__(self, extension_handle): - self._extended_message.ClearExtension(extension_handle) - - def _FindExtensionByName(self, name): - """Tries to find a known extension with the specified name. - - Args: - name: Extension full name. - - Returns: - Extension field descriptor. - """ - return self._extended_message._extensions_by_name.get(name, None) - - def _FindExtensionByNumber(self, number): - """Tries to find a known extension with the field number. - - Args: - number: Extension field number. - - Returns: - Extension field descriptor. - """ - return self._extended_message._extensions_by_number.get(number, None) - - def __iter__(self): - # Return a generator over the populated extension fields - return (f[0] for f in self._extended_message.ListFields() - if f[0].is_extension) - - def __contains__(self, extension_handle): - _VerifyExtensionHandle(self._extended_message, extension_handle) - - if extension_handle not in self._extended_message._fields: - return False - - if extension_handle.label == FieldDescriptor.LABEL_REPEATED: - return bool(self._extended_message._fields.get(extension_handle)) - - if extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE: - value = self._extended_message._fields.get(extension_handle) - # pylint: disable=protected-access - return value is not None and value._is_present_in_parent - - return True diff --git a/scripts/protobuf3/protobuf3/internal/message_listener.py b/scripts/protobuf3/protobuf3/internal/message_listener.py deleted file mode 100644 index 0fc255a..0000000 --- a/scripts/protobuf3/protobuf3/internal/message_listener.py +++ /dev/null @@ -1,78 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Defines a listener interface for observing certain -state transitions on Message objects. - -Also defines a null implementation of this interface. -""" - -__author__ = 'robinson@google.com (Will Robinson)' - - -class MessageListener(object): - - """Listens for modifications made to a message. Meant to be registered via - Message._SetListener(). - - Attributes: - dirty: If True, then calling Modified() would be a no-op. This can be - used to avoid these calls entirely in the common case. - """ - - def Modified(self): - """Called every time the message is modified in such a way that the parent - message may need to be updated. This currently means either: - (a) The message was modified for the first time, so the parent message - should henceforth mark the message as present. - (b) The message's cached byte size became dirty -- i.e. the message was - modified for the first time after a previous call to ByteSize(). - Therefore the parent should also mark its byte size as dirty. - Note that (a) implies (b), since new objects start out with a client cached - size (zero). However, we document (a) explicitly because it is important. - - Modified() will *only* be called in response to one of these two events -- - not every time the sub-message is modified. - - Note that if the listener's |dirty| attribute is true, then calling - Modified at the moment would be a no-op, so it can be skipped. Performance- - sensitive callers should check this attribute directly before calling since - it will be true most of the time. - """ - - raise NotImplementedError - - -class NullMessageListener(object): - - """No-op MessageListener implementation.""" - - def Modified(self): - pass diff --git a/scripts/protobuf3/protobuf3/internal/message_set_extensions_pb2.py b/scripts/protobuf3/protobuf3/internal/message_set_extensions_pb2.py deleted file mode 100644 index 63651a3..0000000 --- a/scripts/protobuf3/protobuf3/internal/message_set_extensions_pb2.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/internal/message_set_extensions.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n5google/protobuf/internal/message_set_extensions.proto\x12\x18google.protobuf.internal\"\x1e\n\x0eTestMessageSet*\x08\x08\x04\x10\xff\xff\xff\xff\x07:\x02\x08\x01\"\xa5\x01\n\x18TestMessageSetExtension1\x12\t\n\x01i\x18\x0f \x01(\x05\x32~\n\x15message_set_extension\x12(.google.protobuf.internal.TestMessageSet\x18\xab\xff\xf6. \x01(\x0b\x32\x32.google.protobuf.internal.TestMessageSetExtension1\"\xa7\x01\n\x18TestMessageSetExtension2\x12\x0b\n\x03str\x18\x19 \x01(\t2~\n\x15message_set_extension\x12(.google.protobuf.internal.TestMessageSet\x18\xca\xff\xf6. \x01(\x0b\x32\x32.google.protobuf.internal.TestMessageSetExtension2\"(\n\x18TestMessageSetExtension3\x12\x0c\n\x04text\x18# \x01(\t:\x7f\n\x16message_set_extension3\x12(.google.protobuf.internal.TestMessageSet\x18\xdf\xff\xf6. \x01(\x0b\x32\x32.google.protobuf.internal.TestMessageSetExtension3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.internal.message_set_extensions_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - TestMessageSet.RegisterExtension(message_set_extension3) - TestMessageSet.RegisterExtension(_TESTMESSAGESETEXTENSION1.extensions_by_name['message_set_extension']) - TestMessageSet.RegisterExtension(_TESTMESSAGESETEXTENSION2.extensions_by_name['message_set_extension']) - - DESCRIPTOR._options = None - _TESTMESSAGESET._options = None - _TESTMESSAGESET._serialized_options = b'\010\001' - _TESTMESSAGESET._serialized_start=83 - _TESTMESSAGESET._serialized_end=113 - _TESTMESSAGESETEXTENSION1._serialized_start=116 - _TESTMESSAGESETEXTENSION1._serialized_end=281 - _TESTMESSAGESETEXTENSION2._serialized_start=284 - _TESTMESSAGESETEXTENSION2._serialized_end=451 - _TESTMESSAGESETEXTENSION3._serialized_start=453 - _TESTMESSAGESETEXTENSION3._serialized_end=493 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/internal/missing_enum_values_pb2.py b/scripts/protobuf3/protobuf3/internal/missing_enum_values_pb2.py deleted file mode 100644 index 5497083..0000000 --- a/scripts/protobuf3/protobuf3/internal/missing_enum_values_pb2.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/internal/missing_enum_values.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n2google/protobuf/internal/missing_enum_values.proto\x12\x1fgoogle.protobuf.python.internal\"\xc1\x02\n\x0eTestEnumValues\x12X\n\x14optional_nested_enum\x18\x01 \x01(\x0e\x32:.google.protobuf.python.internal.TestEnumValues.NestedEnum\x12X\n\x14repeated_nested_enum\x18\x02 \x03(\x0e\x32:.google.protobuf.python.internal.TestEnumValues.NestedEnum\x12Z\n\x12packed_nested_enum\x18\x03 \x03(\x0e\x32:.google.protobuf.python.internal.TestEnumValues.NestedEnumB\x02\x10\x01\"\x1f\n\nNestedEnum\x12\x08\n\x04ZERO\x10\x00\x12\x07\n\x03ONE\x10\x01\"\xd3\x02\n\x15TestMissingEnumValues\x12_\n\x14optional_nested_enum\x18\x01 \x01(\x0e\x32\x41.google.protobuf.python.internal.TestMissingEnumValues.NestedEnum\x12_\n\x14repeated_nested_enum\x18\x02 \x03(\x0e\x32\x41.google.protobuf.python.internal.TestMissingEnumValues.NestedEnum\x12\x61\n\x12packed_nested_enum\x18\x03 \x03(\x0e\x32\x41.google.protobuf.python.internal.TestMissingEnumValues.NestedEnumB\x02\x10\x01\"\x15\n\nNestedEnum\x12\x07\n\x03TWO\x10\x02\"\x1b\n\nJustString\x12\r\n\x05\x64ummy\x18\x01 \x02(\t') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.internal.missing_enum_values_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _TESTENUMVALUES.fields_by_name['packed_nested_enum']._options = None - _TESTENUMVALUES.fields_by_name['packed_nested_enum']._serialized_options = b'\020\001' - _TESTMISSINGENUMVALUES.fields_by_name['packed_nested_enum']._options = None - _TESTMISSINGENUMVALUES.fields_by_name['packed_nested_enum']._serialized_options = b'\020\001' - _TESTENUMVALUES._serialized_start=88 - _TESTENUMVALUES._serialized_end=409 - _TESTENUMVALUES_NESTEDENUM._serialized_start=378 - _TESTENUMVALUES_NESTEDENUM._serialized_end=409 - _TESTMISSINGENUMVALUES._serialized_start=412 - _TESTMISSINGENUMVALUES._serialized_end=751 - _TESTMISSINGENUMVALUES_NESTEDENUM._serialized_start=730 - _TESTMISSINGENUMVALUES_NESTEDENUM._serialized_end=751 - _JUSTSTRING._serialized_start=753 - _JUSTSTRING._serialized_end=780 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/internal/more_extensions_dynamic_pb2.py b/scripts/protobuf3/protobuf3/internal/more_extensions_dynamic_pb2.py deleted file mode 100644 index 0953706..0000000 --- a/scripts/protobuf3/protobuf3/internal/more_extensions_dynamic_pb2.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/internal/more_extensions_dynamic.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from google.protobuf.internal import more_extensions_pb2 as google_dot_protobuf_dot_internal_dot_more__extensions__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n6google/protobuf/internal/more_extensions_dynamic.proto\x12\x18google.protobuf.internal\x1a.google/protobuf/internal/more_extensions.proto\"\x1f\n\x12\x44ynamicMessageType\x12\t\n\x01\x61\x18\x01 \x01(\x05:J\n\x17\x64ynamic_int32_extension\x12).google.protobuf.internal.ExtendedMessage\x18\x64 \x01(\x05:z\n\x19\x64ynamic_message_extension\x12).google.protobuf.internal.ExtendedMessage\x18\x65 \x01(\x0b\x32,.google.protobuf.internal.DynamicMessageType:\x83\x01\n\"repeated_dynamic_message_extension\x12).google.protobuf.internal.ExtendedMessage\x18\x66 \x03(\x0b\x32,.google.protobuf.internal.DynamicMessageType') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.internal.more_extensions_dynamic_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - google_dot_protobuf_dot_internal_dot_more__extensions__pb2.ExtendedMessage.RegisterExtension(dynamic_int32_extension) - google_dot_protobuf_dot_internal_dot_more__extensions__pb2.ExtendedMessage.RegisterExtension(dynamic_message_extension) - google_dot_protobuf_dot_internal_dot_more__extensions__pb2.ExtendedMessage.RegisterExtension(repeated_dynamic_message_extension) - - DESCRIPTOR._options = None - _DYNAMICMESSAGETYPE._serialized_start=132 - _DYNAMICMESSAGETYPE._serialized_end=163 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/internal/more_extensions_pb2.py b/scripts/protobuf3/protobuf3/internal/more_extensions_pb2.py deleted file mode 100644 index 1cfa1b7..0000000 --- a/scripts/protobuf3/protobuf3/internal/more_extensions_pb2.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/internal/more_extensions.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n.google/protobuf/internal/more_extensions.proto\x12\x18google.protobuf.internal\"\x99\x01\n\x0fTopLevelMessage\x12\x41\n\nsubmessage\x18\x01 \x01(\x0b\x32).google.protobuf.internal.ExtendedMessageB\x02(\x01\x12\x43\n\x0enested_message\x18\x02 \x01(\x0b\x32\'.google.protobuf.internal.NestedMessageB\x02(\x01\"R\n\rNestedMessage\x12\x41\n\nsubmessage\x18\x01 \x01(\x0b\x32).google.protobuf.internal.ExtendedMessageB\x02(\x01\"K\n\x0f\x45xtendedMessage\x12\x17\n\x0eoptional_int32\x18\xe9\x07 \x01(\x05\x12\x18\n\x0frepeated_string\x18\xea\x07 \x03(\t*\x05\x08\x01\x10\xe8\x07\"-\n\x0e\x46oreignMessage\x12\x1b\n\x13\x66oreign_message_int\x18\x01 \x01(\x05:I\n\x16optional_int_extension\x12).google.protobuf.internal.ExtendedMessage\x18\x01 \x01(\x05:w\n\x1aoptional_message_extension\x12).google.protobuf.internal.ExtendedMessage\x18\x02 \x01(\x0b\x32(.google.protobuf.internal.ForeignMessage:I\n\x16repeated_int_extension\x12).google.protobuf.internal.ExtendedMessage\x18\x03 \x03(\x05:w\n\x1arepeated_message_extension\x12).google.protobuf.internal.ExtendedMessage\x18\x04 \x03(\x0b\x32(.google.protobuf.internal.ForeignMessage') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.internal.more_extensions_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - ExtendedMessage.RegisterExtension(optional_int_extension) - ExtendedMessage.RegisterExtension(optional_message_extension) - ExtendedMessage.RegisterExtension(repeated_int_extension) - ExtendedMessage.RegisterExtension(repeated_message_extension) - - DESCRIPTOR._options = None - _TOPLEVELMESSAGE.fields_by_name['submessage']._options = None - _TOPLEVELMESSAGE.fields_by_name['submessage']._serialized_options = b'(\001' - _TOPLEVELMESSAGE.fields_by_name['nested_message']._options = None - _TOPLEVELMESSAGE.fields_by_name['nested_message']._serialized_options = b'(\001' - _NESTEDMESSAGE.fields_by_name['submessage']._options = None - _NESTEDMESSAGE.fields_by_name['submessage']._serialized_options = b'(\001' - _TOPLEVELMESSAGE._serialized_start=77 - _TOPLEVELMESSAGE._serialized_end=230 - _NESTEDMESSAGE._serialized_start=232 - _NESTEDMESSAGE._serialized_end=314 - _EXTENDEDMESSAGE._serialized_start=316 - _EXTENDEDMESSAGE._serialized_end=391 - _FOREIGNMESSAGE._serialized_start=393 - _FOREIGNMESSAGE._serialized_end=438 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/internal/more_messages_pb2.py b/scripts/protobuf3/protobuf3/internal/more_messages_pb2.py deleted file mode 100644 index d7f7115..0000000 --- a/scripts/protobuf3/protobuf3/internal/more_messages_pb2.py +++ /dev/null @@ -1,556 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/internal/more_messages.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n,google/protobuf/internal/more_messages.proto\x12\x18google.protobuf.internal\"h\n\x10OutOfOrderFields\x12\x17\n\x0foptional_sint32\x18\x05 \x01(\x11\x12\x17\n\x0foptional_uint32\x18\x03 \x01(\r\x12\x16\n\x0eoptional_int32\x18\x01 \x01(\x05*\x04\x08\x04\x10\x05*\x04\x08\x02\x10\x03\"\xcd\x02\n\x05\x63lass\x12\x1b\n\tint_field\x18\x01 \x01(\x05R\x08json_int\x12\n\n\x02if\x18\x02 \x01(\x05\x12(\n\x02\x61s\x18\x03 \x01(\x0e\x32\x1c.google.protobuf.internal.is\x12\x30\n\nenum_field\x18\x04 \x01(\x0e\x32\x1c.google.protobuf.internal.is\x12>\n\x11nested_enum_field\x18\x05 \x01(\x0e\x32#.google.protobuf.internal.class.for\x12;\n\x0enested_message\x18\x06 \x01(\x0b\x32#.google.protobuf.internal.class.try\x1a\x1c\n\x03try\x12\r\n\x05\x66ield\x18\x01 \x01(\x05*\x06\x08\xe7\x07\x10\x90N\"\x1c\n\x03\x66or\x12\x0b\n\x07\x64\x65\x66\x61ult\x10\x00\x12\x08\n\x04True\x10\x01*\x06\x08\xe7\x07\x10\x90N\"?\n\x0b\x45xtendClass20\n\x06return\x12\x1f.google.protobuf.internal.class\x18\xea\x07 \x01(\x05\"~\n\x0fTestFullKeyword\x12:\n\x06\x66ield1\x18\x01 \x01(\x0b\x32*.google.protobuf.internal.OutOfOrderFields\x12/\n\x06\x66ield2\x18\x02 \x01(\x0b\x32\x1f.google.protobuf.internal.class\"\xa5\x0f\n\x11LotsNestedMessage\x1a\x04\n\x02\x42\x30\x1a\x04\n\x02\x42\x31\x1a\x04\n\x02\x42\x32\x1a\x04\n\x02\x42\x33\x1a\x04\n\x02\x42\x34\x1a\x04\n\x02\x42\x35\x1a\x04\n\x02\x42\x36\x1a\x04\n\x02\x42\x37\x1a\x04\n\x02\x42\x38\x1a\x04\n\x02\x42\x39\x1a\x05\n\x03\x42\x31\x30\x1a\x05\n\x03\x42\x31\x31\x1a\x05\n\x03\x42\x31\x32\x1a\x05\n\x03\x42\x31\x33\x1a\x05\n\x03\x42\x31\x34\x1a\x05\n\x03\x42\x31\x35\x1a\x05\n\x03\x42\x31\x36\x1a\x05\n\x03\x42\x31\x37\x1a\x05\n\x03\x42\x31\x38\x1a\x05\n\x03\x42\x31\x39\x1a\x05\n\x03\x42\x32\x30\x1a\x05\n\x03\x42\x32\x31\x1a\x05\n\x03\x42\x32\x32\x1a\x05\n\x03\x42\x32\x33\x1a\x05\n\x03\x42\x32\x34\x1a\x05\n\x03\x42\x32\x35\x1a\x05\n\x03\x42\x32\x36\x1a\x05\n\x03\x42\x32\x37\x1a\x05\n\x03\x42\x32\x38\x1a\x05\n\x03\x42\x32\x39\x1a\x05\n\x03\x42\x33\x30\x1a\x05\n\x03\x42\x33\x31\x1a\x05\n\x03\x42\x33\x32\x1a\x05\n\x03\x42\x33\x33\x1a\x05\n\x03\x42\x33\x34\x1a\x05\n\x03\x42\x33\x35\x1a\x05\n\x03\x42\x33\x36\x1a\x05\n\x03\x42\x33\x37\x1a\x05\n\x03\x42\x33\x38\x1a\x05\n\x03\x42\x33\x39\x1a\x05\n\x03\x42\x34\x30\x1a\x05\n\x03\x42\x34\x31\x1a\x05\n\x03\x42\x34\x32\x1a\x05\n\x03\x42\x34\x33\x1a\x05\n\x03\x42\x34\x34\x1a\x05\n\x03\x42\x34\x35\x1a\x05\n\x03\x42\x34\x36\x1a\x05\n\x03\x42\x34\x37\x1a\x05\n\x03\x42\x34\x38\x1a\x05\n\x03\x42\x34\x39\x1a\x05\n\x03\x42\x35\x30\x1a\x05\n\x03\x42\x35\x31\x1a\x05\n\x03\x42\x35\x32\x1a\x05\n\x03\x42\x35\x33\x1a\x05\n\x03\x42\x35\x34\x1a\x05\n\x03\x42\x35\x35\x1a\x05\n\x03\x42\x35\x36\x1a\x05\n\x03\x42\x35\x37\x1a\x05\n\x03\x42\x35\x38\x1a\x05\n\x03\x42\x35\x39\x1a\x05\n\x03\x42\x36\x30\x1a\x05\n\x03\x42\x36\x31\x1a\x05\n\x03\x42\x36\x32\x1a\x05\n\x03\x42\x36\x33\x1a\x05\n\x03\x42\x36\x34\x1a\x05\n\x03\x42\x36\x35\x1a\x05\n\x03\x42\x36\x36\x1a\x05\n\x03\x42\x36\x37\x1a\x05\n\x03\x42\x36\x38\x1a\x05\n\x03\x42\x36\x39\x1a\x05\n\x03\x42\x37\x30\x1a\x05\n\x03\x42\x37\x31\x1a\x05\n\x03\x42\x37\x32\x1a\x05\n\x03\x42\x37\x33\x1a\x05\n\x03\x42\x37\x34\x1a\x05\n\x03\x42\x37\x35\x1a\x05\n\x03\x42\x37\x36\x1a\x05\n\x03\x42\x37\x37\x1a\x05\n\x03\x42\x37\x38\x1a\x05\n\x03\x42\x37\x39\x1a\x05\n\x03\x42\x38\x30\x1a\x05\n\x03\x42\x38\x31\x1a\x05\n\x03\x42\x38\x32\x1a\x05\n\x03\x42\x38\x33\x1a\x05\n\x03\x42\x38\x34\x1a\x05\n\x03\x42\x38\x35\x1a\x05\n\x03\x42\x38\x36\x1a\x05\n\x03\x42\x38\x37\x1a\x05\n\x03\x42\x38\x38\x1a\x05\n\x03\x42\x38\x39\x1a\x05\n\x03\x42\x39\x30\x1a\x05\n\x03\x42\x39\x31\x1a\x05\n\x03\x42\x39\x32\x1a\x05\n\x03\x42\x39\x33\x1a\x05\n\x03\x42\x39\x34\x1a\x05\n\x03\x42\x39\x35\x1a\x05\n\x03\x42\x39\x36\x1a\x05\n\x03\x42\x39\x37\x1a\x05\n\x03\x42\x39\x38\x1a\x05\n\x03\x42\x39\x39\x1a\x06\n\x04\x42\x31\x30\x30\x1a\x06\n\x04\x42\x31\x30\x31\x1a\x06\n\x04\x42\x31\x30\x32\x1a\x06\n\x04\x42\x31\x30\x33\x1a\x06\n\x04\x42\x31\x30\x34\x1a\x06\n\x04\x42\x31\x30\x35\x1a\x06\n\x04\x42\x31\x30\x36\x1a\x06\n\x04\x42\x31\x30\x37\x1a\x06\n\x04\x42\x31\x30\x38\x1a\x06\n\x04\x42\x31\x30\x39\x1a\x06\n\x04\x42\x31\x31\x30\x1a\x06\n\x04\x42\x31\x31\x31\x1a\x06\n\x04\x42\x31\x31\x32\x1a\x06\n\x04\x42\x31\x31\x33\x1a\x06\n\x04\x42\x31\x31\x34\x1a\x06\n\x04\x42\x31\x31\x35\x1a\x06\n\x04\x42\x31\x31\x36\x1a\x06\n\x04\x42\x31\x31\x37\x1a\x06\n\x04\x42\x31\x31\x38\x1a\x06\n\x04\x42\x31\x31\x39\x1a\x06\n\x04\x42\x31\x32\x30\x1a\x06\n\x04\x42\x31\x32\x31\x1a\x06\n\x04\x42\x31\x32\x32\x1a\x06\n\x04\x42\x31\x32\x33\x1a\x06\n\x04\x42\x31\x32\x34\x1a\x06\n\x04\x42\x31\x32\x35\x1a\x06\n\x04\x42\x31\x32\x36\x1a\x06\n\x04\x42\x31\x32\x37\x1a\x06\n\x04\x42\x31\x32\x38\x1a\x06\n\x04\x42\x31\x32\x39\x1a\x06\n\x04\x42\x31\x33\x30\x1a\x06\n\x04\x42\x31\x33\x31\x1a\x06\n\x04\x42\x31\x33\x32\x1a\x06\n\x04\x42\x31\x33\x33\x1a\x06\n\x04\x42\x31\x33\x34\x1a\x06\n\x04\x42\x31\x33\x35\x1a\x06\n\x04\x42\x31\x33\x36\x1a\x06\n\x04\x42\x31\x33\x37\x1a\x06\n\x04\x42\x31\x33\x38\x1a\x06\n\x04\x42\x31\x33\x39\x1a\x06\n\x04\x42\x31\x34\x30\x1a\x06\n\x04\x42\x31\x34\x31\x1a\x06\n\x04\x42\x31\x34\x32\x1a\x06\n\x04\x42\x31\x34\x33\x1a\x06\n\x04\x42\x31\x34\x34\x1a\x06\n\x04\x42\x31\x34\x35\x1a\x06\n\x04\x42\x31\x34\x36\x1a\x06\n\x04\x42\x31\x34\x37\x1a\x06\n\x04\x42\x31\x34\x38\x1a\x06\n\x04\x42\x31\x34\x39\x1a\x06\n\x04\x42\x31\x35\x30\x1a\x06\n\x04\x42\x31\x35\x31\x1a\x06\n\x04\x42\x31\x35\x32\x1a\x06\n\x04\x42\x31\x35\x33\x1a\x06\n\x04\x42\x31\x35\x34\x1a\x06\n\x04\x42\x31\x35\x35\x1a\x06\n\x04\x42\x31\x35\x36\x1a\x06\n\x04\x42\x31\x35\x37\x1a\x06\n\x04\x42\x31\x35\x38\x1a\x06\n\x04\x42\x31\x35\x39\x1a\x06\n\x04\x42\x31\x36\x30\x1a\x06\n\x04\x42\x31\x36\x31\x1a\x06\n\x04\x42\x31\x36\x32\x1a\x06\n\x04\x42\x31\x36\x33\x1a\x06\n\x04\x42\x31\x36\x34\x1a\x06\n\x04\x42\x31\x36\x35\x1a\x06\n\x04\x42\x31\x36\x36\x1a\x06\n\x04\x42\x31\x36\x37\x1a\x06\n\x04\x42\x31\x36\x38\x1a\x06\n\x04\x42\x31\x36\x39\x1a\x06\n\x04\x42\x31\x37\x30\x1a\x06\n\x04\x42\x31\x37\x31\x1a\x06\n\x04\x42\x31\x37\x32\x1a\x06\n\x04\x42\x31\x37\x33\x1a\x06\n\x04\x42\x31\x37\x34\x1a\x06\n\x04\x42\x31\x37\x35\x1a\x06\n\x04\x42\x31\x37\x36\x1a\x06\n\x04\x42\x31\x37\x37\x1a\x06\n\x04\x42\x31\x37\x38\x1a\x06\n\x04\x42\x31\x37\x39\x1a\x06\n\x04\x42\x31\x38\x30\x1a\x06\n\x04\x42\x31\x38\x31\x1a\x06\n\x04\x42\x31\x38\x32\x1a\x06\n\x04\x42\x31\x38\x33\x1a\x06\n\x04\x42\x31\x38\x34\x1a\x06\n\x04\x42\x31\x38\x35\x1a\x06\n\x04\x42\x31\x38\x36\x1a\x06\n\x04\x42\x31\x38\x37\x1a\x06\n\x04\x42\x31\x38\x38\x1a\x06\n\x04\x42\x31\x38\x39\x1a\x06\n\x04\x42\x31\x39\x30\x1a\x06\n\x04\x42\x31\x39\x31\x1a\x06\n\x04\x42\x31\x39\x32\x1a\x06\n\x04\x42\x31\x39\x33\x1a\x06\n\x04\x42\x31\x39\x34\x1a\x06\n\x04\x42\x31\x39\x35\x1a\x06\n\x04\x42\x31\x39\x36\x1a\x06\n\x04\x42\x31\x39\x37\x1a\x06\n\x04\x42\x31\x39\x38\x1a\x06\n\x04\x42\x31\x39\x39\x1a\x06\n\x04\x42\x32\x30\x30\x1a\x06\n\x04\x42\x32\x30\x31\x1a\x06\n\x04\x42\x32\x30\x32\x1a\x06\n\x04\x42\x32\x30\x33\x1a\x06\n\x04\x42\x32\x30\x34\x1a\x06\n\x04\x42\x32\x30\x35\x1a\x06\n\x04\x42\x32\x30\x36\x1a\x06\n\x04\x42\x32\x30\x37\x1a\x06\n\x04\x42\x32\x30\x38\x1a\x06\n\x04\x42\x32\x30\x39\x1a\x06\n\x04\x42\x32\x31\x30\x1a\x06\n\x04\x42\x32\x31\x31\x1a\x06\n\x04\x42\x32\x31\x32\x1a\x06\n\x04\x42\x32\x31\x33\x1a\x06\n\x04\x42\x32\x31\x34\x1a\x06\n\x04\x42\x32\x31\x35\x1a\x06\n\x04\x42\x32\x31\x36\x1a\x06\n\x04\x42\x32\x31\x37\x1a\x06\n\x04\x42\x32\x31\x38\x1a\x06\n\x04\x42\x32\x31\x39\x1a\x06\n\x04\x42\x32\x32\x30\x1a\x06\n\x04\x42\x32\x32\x31\x1a\x06\n\x04\x42\x32\x32\x32\x1a\x06\n\x04\x42\x32\x32\x33\x1a\x06\n\x04\x42\x32\x32\x34\x1a\x06\n\x04\x42\x32\x32\x35\x1a\x06\n\x04\x42\x32\x32\x36\x1a\x06\n\x04\x42\x32\x32\x37\x1a\x06\n\x04\x42\x32\x32\x38\x1a\x06\n\x04\x42\x32\x32\x39\x1a\x06\n\x04\x42\x32\x33\x30\x1a\x06\n\x04\x42\x32\x33\x31\x1a\x06\n\x04\x42\x32\x33\x32\x1a\x06\n\x04\x42\x32\x33\x33\x1a\x06\n\x04\x42\x32\x33\x34\x1a\x06\n\x04\x42\x32\x33\x35\x1a\x06\n\x04\x42\x32\x33\x36\x1a\x06\n\x04\x42\x32\x33\x37\x1a\x06\n\x04\x42\x32\x33\x38\x1a\x06\n\x04\x42\x32\x33\x39\x1a\x06\n\x04\x42\x32\x34\x30\x1a\x06\n\x04\x42\x32\x34\x31\x1a\x06\n\x04\x42\x32\x34\x32\x1a\x06\n\x04\x42\x32\x34\x33\x1a\x06\n\x04\x42\x32\x34\x34\x1a\x06\n\x04\x42\x32\x34\x35\x1a\x06\n\x04\x42\x32\x34\x36\x1a\x06\n\x04\x42\x32\x34\x37\x1a\x06\n\x04\x42\x32\x34\x38\x1a\x06\n\x04\x42\x32\x34\x39\x1a\x06\n\x04\x42\x32\x35\x30\x1a\x06\n\x04\x42\x32\x35\x31\x1a\x06\n\x04\x42\x32\x35\x32\x1a\x06\n\x04\x42\x32\x35\x33\x1a\x06\n\x04\x42\x32\x35\x34\x1a\x06\n\x04\x42\x32\x35\x35*\x1b\n\x02is\x12\x0b\n\x07\x64\x65\x66\x61ult\x10\x00\x12\x08\n\x04\x65lse\x10\x01:C\n\x0foptional_uint64\x12*.google.protobuf.internal.OutOfOrderFields\x18\x04 \x01(\x04:B\n\x0eoptional_int64\x12*.google.protobuf.internal.OutOfOrderFields\x18\x02 \x01(\x03:2\n\x08\x63ontinue\x12\x1f.google.protobuf.internal.class\x18\xe9\x07 \x01(\x05:2\n\x04with\x12#.google.protobuf.internal.class.try\x18\xe9\x07 \x01(\x05') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.internal.more_messages_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - OutOfOrderFields.RegisterExtension(optional_uint64) - OutOfOrderFields.RegisterExtension(optional_int64) - globals()['class'].RegisterExtension(globals()['continue']) - getattr(globals()['class'], 'try').RegisterExtension(globals()['with']) - globals()['class'].RegisterExtension(_EXTENDCLASS.extensions_by_name['return']) - - DESCRIPTOR._options = None - _IS._serialized_start=2669 - _IS._serialized_end=2696 - _OUTOFORDERFIELDS._serialized_start=74 - _OUTOFORDERFIELDS._serialized_end=178 - _CLASS._serialized_start=181 - _CLASS._serialized_end=514 - _CLASS_TRY._serialized_start=448 - _CLASS_TRY._serialized_end=476 - _CLASS_FOR._serialized_start=478 - _CLASS_FOR._serialized_end=506 - _EXTENDCLASS._serialized_start=516 - _EXTENDCLASS._serialized_end=579 - _TESTFULLKEYWORD._serialized_start=581 - _TESTFULLKEYWORD._serialized_end=707 - _LOTSNESTEDMESSAGE._serialized_start=710 - _LOTSNESTEDMESSAGE._serialized_end=2667 - _LOTSNESTEDMESSAGE_B0._serialized_start=731 - _LOTSNESTEDMESSAGE_B0._serialized_end=735 - _LOTSNESTEDMESSAGE_B1._serialized_start=737 - _LOTSNESTEDMESSAGE_B1._serialized_end=741 - _LOTSNESTEDMESSAGE_B2._serialized_start=743 - _LOTSNESTEDMESSAGE_B2._serialized_end=747 - _LOTSNESTEDMESSAGE_B3._serialized_start=749 - _LOTSNESTEDMESSAGE_B3._serialized_end=753 - _LOTSNESTEDMESSAGE_B4._serialized_start=755 - _LOTSNESTEDMESSAGE_B4._serialized_end=759 - _LOTSNESTEDMESSAGE_B5._serialized_start=761 - _LOTSNESTEDMESSAGE_B5._serialized_end=765 - _LOTSNESTEDMESSAGE_B6._serialized_start=767 - _LOTSNESTEDMESSAGE_B6._serialized_end=771 - _LOTSNESTEDMESSAGE_B7._serialized_start=773 - _LOTSNESTEDMESSAGE_B7._serialized_end=777 - _LOTSNESTEDMESSAGE_B8._serialized_start=779 - _LOTSNESTEDMESSAGE_B8._serialized_end=783 - _LOTSNESTEDMESSAGE_B9._serialized_start=785 - _LOTSNESTEDMESSAGE_B9._serialized_end=789 - _LOTSNESTEDMESSAGE_B10._serialized_start=791 - _LOTSNESTEDMESSAGE_B10._serialized_end=796 - _LOTSNESTEDMESSAGE_B11._serialized_start=798 - _LOTSNESTEDMESSAGE_B11._serialized_end=803 - _LOTSNESTEDMESSAGE_B12._serialized_start=805 - _LOTSNESTEDMESSAGE_B12._serialized_end=810 - _LOTSNESTEDMESSAGE_B13._serialized_start=812 - _LOTSNESTEDMESSAGE_B13._serialized_end=817 - _LOTSNESTEDMESSAGE_B14._serialized_start=819 - _LOTSNESTEDMESSAGE_B14._serialized_end=824 - _LOTSNESTEDMESSAGE_B15._serialized_start=826 - _LOTSNESTEDMESSAGE_B15._serialized_end=831 - _LOTSNESTEDMESSAGE_B16._serialized_start=833 - _LOTSNESTEDMESSAGE_B16._serialized_end=838 - _LOTSNESTEDMESSAGE_B17._serialized_start=840 - _LOTSNESTEDMESSAGE_B17._serialized_end=845 - _LOTSNESTEDMESSAGE_B18._serialized_start=847 - _LOTSNESTEDMESSAGE_B18._serialized_end=852 - _LOTSNESTEDMESSAGE_B19._serialized_start=854 - _LOTSNESTEDMESSAGE_B19._serialized_end=859 - _LOTSNESTEDMESSAGE_B20._serialized_start=861 - _LOTSNESTEDMESSAGE_B20._serialized_end=866 - _LOTSNESTEDMESSAGE_B21._serialized_start=868 - _LOTSNESTEDMESSAGE_B21._serialized_end=873 - _LOTSNESTEDMESSAGE_B22._serialized_start=875 - _LOTSNESTEDMESSAGE_B22._serialized_end=880 - _LOTSNESTEDMESSAGE_B23._serialized_start=882 - _LOTSNESTEDMESSAGE_B23._serialized_end=887 - _LOTSNESTEDMESSAGE_B24._serialized_start=889 - _LOTSNESTEDMESSAGE_B24._serialized_end=894 - _LOTSNESTEDMESSAGE_B25._serialized_start=896 - _LOTSNESTEDMESSAGE_B25._serialized_end=901 - _LOTSNESTEDMESSAGE_B26._serialized_start=903 - _LOTSNESTEDMESSAGE_B26._serialized_end=908 - _LOTSNESTEDMESSAGE_B27._serialized_start=910 - _LOTSNESTEDMESSAGE_B27._serialized_end=915 - _LOTSNESTEDMESSAGE_B28._serialized_start=917 - _LOTSNESTEDMESSAGE_B28._serialized_end=922 - _LOTSNESTEDMESSAGE_B29._serialized_start=924 - _LOTSNESTEDMESSAGE_B29._serialized_end=929 - _LOTSNESTEDMESSAGE_B30._serialized_start=931 - _LOTSNESTEDMESSAGE_B30._serialized_end=936 - _LOTSNESTEDMESSAGE_B31._serialized_start=938 - _LOTSNESTEDMESSAGE_B31._serialized_end=943 - _LOTSNESTEDMESSAGE_B32._serialized_start=945 - _LOTSNESTEDMESSAGE_B32._serialized_end=950 - _LOTSNESTEDMESSAGE_B33._serialized_start=952 - _LOTSNESTEDMESSAGE_B33._serialized_end=957 - _LOTSNESTEDMESSAGE_B34._serialized_start=959 - _LOTSNESTEDMESSAGE_B34._serialized_end=964 - _LOTSNESTEDMESSAGE_B35._serialized_start=966 - _LOTSNESTEDMESSAGE_B35._serialized_end=971 - _LOTSNESTEDMESSAGE_B36._serialized_start=973 - _LOTSNESTEDMESSAGE_B36._serialized_end=978 - _LOTSNESTEDMESSAGE_B37._serialized_start=980 - _LOTSNESTEDMESSAGE_B37._serialized_end=985 - _LOTSNESTEDMESSAGE_B38._serialized_start=987 - _LOTSNESTEDMESSAGE_B38._serialized_end=992 - _LOTSNESTEDMESSAGE_B39._serialized_start=994 - _LOTSNESTEDMESSAGE_B39._serialized_end=999 - _LOTSNESTEDMESSAGE_B40._serialized_start=1001 - _LOTSNESTEDMESSAGE_B40._serialized_end=1006 - _LOTSNESTEDMESSAGE_B41._serialized_start=1008 - _LOTSNESTEDMESSAGE_B41._serialized_end=1013 - _LOTSNESTEDMESSAGE_B42._serialized_start=1015 - _LOTSNESTEDMESSAGE_B42._serialized_end=1020 - _LOTSNESTEDMESSAGE_B43._serialized_start=1022 - _LOTSNESTEDMESSAGE_B43._serialized_end=1027 - _LOTSNESTEDMESSAGE_B44._serialized_start=1029 - _LOTSNESTEDMESSAGE_B44._serialized_end=1034 - _LOTSNESTEDMESSAGE_B45._serialized_start=1036 - _LOTSNESTEDMESSAGE_B45._serialized_end=1041 - _LOTSNESTEDMESSAGE_B46._serialized_start=1043 - _LOTSNESTEDMESSAGE_B46._serialized_end=1048 - _LOTSNESTEDMESSAGE_B47._serialized_start=1050 - _LOTSNESTEDMESSAGE_B47._serialized_end=1055 - _LOTSNESTEDMESSAGE_B48._serialized_start=1057 - _LOTSNESTEDMESSAGE_B48._serialized_end=1062 - _LOTSNESTEDMESSAGE_B49._serialized_start=1064 - _LOTSNESTEDMESSAGE_B49._serialized_end=1069 - _LOTSNESTEDMESSAGE_B50._serialized_start=1071 - _LOTSNESTEDMESSAGE_B50._serialized_end=1076 - _LOTSNESTEDMESSAGE_B51._serialized_start=1078 - _LOTSNESTEDMESSAGE_B51._serialized_end=1083 - _LOTSNESTEDMESSAGE_B52._serialized_start=1085 - _LOTSNESTEDMESSAGE_B52._serialized_end=1090 - _LOTSNESTEDMESSAGE_B53._serialized_start=1092 - _LOTSNESTEDMESSAGE_B53._serialized_end=1097 - _LOTSNESTEDMESSAGE_B54._serialized_start=1099 - _LOTSNESTEDMESSAGE_B54._serialized_end=1104 - _LOTSNESTEDMESSAGE_B55._serialized_start=1106 - _LOTSNESTEDMESSAGE_B55._serialized_end=1111 - _LOTSNESTEDMESSAGE_B56._serialized_start=1113 - _LOTSNESTEDMESSAGE_B56._serialized_end=1118 - _LOTSNESTEDMESSAGE_B57._serialized_start=1120 - _LOTSNESTEDMESSAGE_B57._serialized_end=1125 - _LOTSNESTEDMESSAGE_B58._serialized_start=1127 - _LOTSNESTEDMESSAGE_B58._serialized_end=1132 - _LOTSNESTEDMESSAGE_B59._serialized_start=1134 - _LOTSNESTEDMESSAGE_B59._serialized_end=1139 - _LOTSNESTEDMESSAGE_B60._serialized_start=1141 - _LOTSNESTEDMESSAGE_B60._serialized_end=1146 - _LOTSNESTEDMESSAGE_B61._serialized_start=1148 - _LOTSNESTEDMESSAGE_B61._serialized_end=1153 - _LOTSNESTEDMESSAGE_B62._serialized_start=1155 - _LOTSNESTEDMESSAGE_B62._serialized_end=1160 - _LOTSNESTEDMESSAGE_B63._serialized_start=1162 - _LOTSNESTEDMESSAGE_B63._serialized_end=1167 - _LOTSNESTEDMESSAGE_B64._serialized_start=1169 - _LOTSNESTEDMESSAGE_B64._serialized_end=1174 - _LOTSNESTEDMESSAGE_B65._serialized_start=1176 - _LOTSNESTEDMESSAGE_B65._serialized_end=1181 - _LOTSNESTEDMESSAGE_B66._serialized_start=1183 - _LOTSNESTEDMESSAGE_B66._serialized_end=1188 - _LOTSNESTEDMESSAGE_B67._serialized_start=1190 - _LOTSNESTEDMESSAGE_B67._serialized_end=1195 - _LOTSNESTEDMESSAGE_B68._serialized_start=1197 - _LOTSNESTEDMESSAGE_B68._serialized_end=1202 - _LOTSNESTEDMESSAGE_B69._serialized_start=1204 - _LOTSNESTEDMESSAGE_B69._serialized_end=1209 - _LOTSNESTEDMESSAGE_B70._serialized_start=1211 - _LOTSNESTEDMESSAGE_B70._serialized_end=1216 - _LOTSNESTEDMESSAGE_B71._serialized_start=1218 - _LOTSNESTEDMESSAGE_B71._serialized_end=1223 - _LOTSNESTEDMESSAGE_B72._serialized_start=1225 - _LOTSNESTEDMESSAGE_B72._serialized_end=1230 - _LOTSNESTEDMESSAGE_B73._serialized_start=1232 - _LOTSNESTEDMESSAGE_B73._serialized_end=1237 - _LOTSNESTEDMESSAGE_B74._serialized_start=1239 - _LOTSNESTEDMESSAGE_B74._serialized_end=1244 - _LOTSNESTEDMESSAGE_B75._serialized_start=1246 - _LOTSNESTEDMESSAGE_B75._serialized_end=1251 - _LOTSNESTEDMESSAGE_B76._serialized_start=1253 - _LOTSNESTEDMESSAGE_B76._serialized_end=1258 - _LOTSNESTEDMESSAGE_B77._serialized_start=1260 - _LOTSNESTEDMESSAGE_B77._serialized_end=1265 - _LOTSNESTEDMESSAGE_B78._serialized_start=1267 - _LOTSNESTEDMESSAGE_B78._serialized_end=1272 - _LOTSNESTEDMESSAGE_B79._serialized_start=1274 - _LOTSNESTEDMESSAGE_B79._serialized_end=1279 - _LOTSNESTEDMESSAGE_B80._serialized_start=1281 - _LOTSNESTEDMESSAGE_B80._serialized_end=1286 - _LOTSNESTEDMESSAGE_B81._serialized_start=1288 - _LOTSNESTEDMESSAGE_B81._serialized_end=1293 - _LOTSNESTEDMESSAGE_B82._serialized_start=1295 - _LOTSNESTEDMESSAGE_B82._serialized_end=1300 - _LOTSNESTEDMESSAGE_B83._serialized_start=1302 - _LOTSNESTEDMESSAGE_B83._serialized_end=1307 - _LOTSNESTEDMESSAGE_B84._serialized_start=1309 - _LOTSNESTEDMESSAGE_B84._serialized_end=1314 - _LOTSNESTEDMESSAGE_B85._serialized_start=1316 - _LOTSNESTEDMESSAGE_B85._serialized_end=1321 - _LOTSNESTEDMESSAGE_B86._serialized_start=1323 - _LOTSNESTEDMESSAGE_B86._serialized_end=1328 - _LOTSNESTEDMESSAGE_B87._serialized_start=1330 - _LOTSNESTEDMESSAGE_B87._serialized_end=1335 - _LOTSNESTEDMESSAGE_B88._serialized_start=1337 - _LOTSNESTEDMESSAGE_B88._serialized_end=1342 - _LOTSNESTEDMESSAGE_B89._serialized_start=1344 - _LOTSNESTEDMESSAGE_B89._serialized_end=1349 - _LOTSNESTEDMESSAGE_B90._serialized_start=1351 - _LOTSNESTEDMESSAGE_B90._serialized_end=1356 - _LOTSNESTEDMESSAGE_B91._serialized_start=1358 - _LOTSNESTEDMESSAGE_B91._serialized_end=1363 - _LOTSNESTEDMESSAGE_B92._serialized_start=1365 - _LOTSNESTEDMESSAGE_B92._serialized_end=1370 - _LOTSNESTEDMESSAGE_B93._serialized_start=1372 - _LOTSNESTEDMESSAGE_B93._serialized_end=1377 - _LOTSNESTEDMESSAGE_B94._serialized_start=1379 - _LOTSNESTEDMESSAGE_B94._serialized_end=1384 - _LOTSNESTEDMESSAGE_B95._serialized_start=1386 - _LOTSNESTEDMESSAGE_B95._serialized_end=1391 - _LOTSNESTEDMESSAGE_B96._serialized_start=1393 - _LOTSNESTEDMESSAGE_B96._serialized_end=1398 - _LOTSNESTEDMESSAGE_B97._serialized_start=1400 - _LOTSNESTEDMESSAGE_B97._serialized_end=1405 - _LOTSNESTEDMESSAGE_B98._serialized_start=1407 - _LOTSNESTEDMESSAGE_B98._serialized_end=1412 - _LOTSNESTEDMESSAGE_B99._serialized_start=1414 - _LOTSNESTEDMESSAGE_B99._serialized_end=1419 - _LOTSNESTEDMESSAGE_B100._serialized_start=1421 - _LOTSNESTEDMESSAGE_B100._serialized_end=1427 - _LOTSNESTEDMESSAGE_B101._serialized_start=1429 - _LOTSNESTEDMESSAGE_B101._serialized_end=1435 - _LOTSNESTEDMESSAGE_B102._serialized_start=1437 - _LOTSNESTEDMESSAGE_B102._serialized_end=1443 - _LOTSNESTEDMESSAGE_B103._serialized_start=1445 - _LOTSNESTEDMESSAGE_B103._serialized_end=1451 - _LOTSNESTEDMESSAGE_B104._serialized_start=1453 - _LOTSNESTEDMESSAGE_B104._serialized_end=1459 - _LOTSNESTEDMESSAGE_B105._serialized_start=1461 - _LOTSNESTEDMESSAGE_B105._serialized_end=1467 - _LOTSNESTEDMESSAGE_B106._serialized_start=1469 - _LOTSNESTEDMESSAGE_B106._serialized_end=1475 - _LOTSNESTEDMESSAGE_B107._serialized_start=1477 - _LOTSNESTEDMESSAGE_B107._serialized_end=1483 - _LOTSNESTEDMESSAGE_B108._serialized_start=1485 - _LOTSNESTEDMESSAGE_B108._serialized_end=1491 - _LOTSNESTEDMESSAGE_B109._serialized_start=1493 - _LOTSNESTEDMESSAGE_B109._serialized_end=1499 - _LOTSNESTEDMESSAGE_B110._serialized_start=1501 - _LOTSNESTEDMESSAGE_B110._serialized_end=1507 - _LOTSNESTEDMESSAGE_B111._serialized_start=1509 - _LOTSNESTEDMESSAGE_B111._serialized_end=1515 - _LOTSNESTEDMESSAGE_B112._serialized_start=1517 - _LOTSNESTEDMESSAGE_B112._serialized_end=1523 - _LOTSNESTEDMESSAGE_B113._serialized_start=1525 - _LOTSNESTEDMESSAGE_B113._serialized_end=1531 - _LOTSNESTEDMESSAGE_B114._serialized_start=1533 - _LOTSNESTEDMESSAGE_B114._serialized_end=1539 - _LOTSNESTEDMESSAGE_B115._serialized_start=1541 - _LOTSNESTEDMESSAGE_B115._serialized_end=1547 - _LOTSNESTEDMESSAGE_B116._serialized_start=1549 - _LOTSNESTEDMESSAGE_B116._serialized_end=1555 - _LOTSNESTEDMESSAGE_B117._serialized_start=1557 - _LOTSNESTEDMESSAGE_B117._serialized_end=1563 - _LOTSNESTEDMESSAGE_B118._serialized_start=1565 - _LOTSNESTEDMESSAGE_B118._serialized_end=1571 - _LOTSNESTEDMESSAGE_B119._serialized_start=1573 - _LOTSNESTEDMESSAGE_B119._serialized_end=1579 - _LOTSNESTEDMESSAGE_B120._serialized_start=1581 - _LOTSNESTEDMESSAGE_B120._serialized_end=1587 - _LOTSNESTEDMESSAGE_B121._serialized_start=1589 - _LOTSNESTEDMESSAGE_B121._serialized_end=1595 - _LOTSNESTEDMESSAGE_B122._serialized_start=1597 - _LOTSNESTEDMESSAGE_B122._serialized_end=1603 - _LOTSNESTEDMESSAGE_B123._serialized_start=1605 - _LOTSNESTEDMESSAGE_B123._serialized_end=1611 - _LOTSNESTEDMESSAGE_B124._serialized_start=1613 - _LOTSNESTEDMESSAGE_B124._serialized_end=1619 - _LOTSNESTEDMESSAGE_B125._serialized_start=1621 - _LOTSNESTEDMESSAGE_B125._serialized_end=1627 - _LOTSNESTEDMESSAGE_B126._serialized_start=1629 - _LOTSNESTEDMESSAGE_B126._serialized_end=1635 - _LOTSNESTEDMESSAGE_B127._serialized_start=1637 - _LOTSNESTEDMESSAGE_B127._serialized_end=1643 - _LOTSNESTEDMESSAGE_B128._serialized_start=1645 - _LOTSNESTEDMESSAGE_B128._serialized_end=1651 - _LOTSNESTEDMESSAGE_B129._serialized_start=1653 - _LOTSNESTEDMESSAGE_B129._serialized_end=1659 - _LOTSNESTEDMESSAGE_B130._serialized_start=1661 - _LOTSNESTEDMESSAGE_B130._serialized_end=1667 - _LOTSNESTEDMESSAGE_B131._serialized_start=1669 - _LOTSNESTEDMESSAGE_B131._serialized_end=1675 - _LOTSNESTEDMESSAGE_B132._serialized_start=1677 - _LOTSNESTEDMESSAGE_B132._serialized_end=1683 - _LOTSNESTEDMESSAGE_B133._serialized_start=1685 - _LOTSNESTEDMESSAGE_B133._serialized_end=1691 - _LOTSNESTEDMESSAGE_B134._serialized_start=1693 - _LOTSNESTEDMESSAGE_B134._serialized_end=1699 - _LOTSNESTEDMESSAGE_B135._serialized_start=1701 - _LOTSNESTEDMESSAGE_B135._serialized_end=1707 - _LOTSNESTEDMESSAGE_B136._serialized_start=1709 - _LOTSNESTEDMESSAGE_B136._serialized_end=1715 - _LOTSNESTEDMESSAGE_B137._serialized_start=1717 - _LOTSNESTEDMESSAGE_B137._serialized_end=1723 - _LOTSNESTEDMESSAGE_B138._serialized_start=1725 - _LOTSNESTEDMESSAGE_B138._serialized_end=1731 - _LOTSNESTEDMESSAGE_B139._serialized_start=1733 - _LOTSNESTEDMESSAGE_B139._serialized_end=1739 - _LOTSNESTEDMESSAGE_B140._serialized_start=1741 - _LOTSNESTEDMESSAGE_B140._serialized_end=1747 - _LOTSNESTEDMESSAGE_B141._serialized_start=1749 - _LOTSNESTEDMESSAGE_B141._serialized_end=1755 - _LOTSNESTEDMESSAGE_B142._serialized_start=1757 - _LOTSNESTEDMESSAGE_B142._serialized_end=1763 - _LOTSNESTEDMESSAGE_B143._serialized_start=1765 - _LOTSNESTEDMESSAGE_B143._serialized_end=1771 - _LOTSNESTEDMESSAGE_B144._serialized_start=1773 - _LOTSNESTEDMESSAGE_B144._serialized_end=1779 - _LOTSNESTEDMESSAGE_B145._serialized_start=1781 - _LOTSNESTEDMESSAGE_B145._serialized_end=1787 - _LOTSNESTEDMESSAGE_B146._serialized_start=1789 - _LOTSNESTEDMESSAGE_B146._serialized_end=1795 - _LOTSNESTEDMESSAGE_B147._serialized_start=1797 - _LOTSNESTEDMESSAGE_B147._serialized_end=1803 - _LOTSNESTEDMESSAGE_B148._serialized_start=1805 - _LOTSNESTEDMESSAGE_B148._serialized_end=1811 - _LOTSNESTEDMESSAGE_B149._serialized_start=1813 - _LOTSNESTEDMESSAGE_B149._serialized_end=1819 - _LOTSNESTEDMESSAGE_B150._serialized_start=1821 - _LOTSNESTEDMESSAGE_B150._serialized_end=1827 - _LOTSNESTEDMESSAGE_B151._serialized_start=1829 - _LOTSNESTEDMESSAGE_B151._serialized_end=1835 - _LOTSNESTEDMESSAGE_B152._serialized_start=1837 - _LOTSNESTEDMESSAGE_B152._serialized_end=1843 - _LOTSNESTEDMESSAGE_B153._serialized_start=1845 - _LOTSNESTEDMESSAGE_B153._serialized_end=1851 - _LOTSNESTEDMESSAGE_B154._serialized_start=1853 - _LOTSNESTEDMESSAGE_B154._serialized_end=1859 - _LOTSNESTEDMESSAGE_B155._serialized_start=1861 - _LOTSNESTEDMESSAGE_B155._serialized_end=1867 - _LOTSNESTEDMESSAGE_B156._serialized_start=1869 - _LOTSNESTEDMESSAGE_B156._serialized_end=1875 - _LOTSNESTEDMESSAGE_B157._serialized_start=1877 - _LOTSNESTEDMESSAGE_B157._serialized_end=1883 - _LOTSNESTEDMESSAGE_B158._serialized_start=1885 - _LOTSNESTEDMESSAGE_B158._serialized_end=1891 - _LOTSNESTEDMESSAGE_B159._serialized_start=1893 - _LOTSNESTEDMESSAGE_B159._serialized_end=1899 - _LOTSNESTEDMESSAGE_B160._serialized_start=1901 - _LOTSNESTEDMESSAGE_B160._serialized_end=1907 - _LOTSNESTEDMESSAGE_B161._serialized_start=1909 - _LOTSNESTEDMESSAGE_B161._serialized_end=1915 - _LOTSNESTEDMESSAGE_B162._serialized_start=1917 - _LOTSNESTEDMESSAGE_B162._serialized_end=1923 - _LOTSNESTEDMESSAGE_B163._serialized_start=1925 - _LOTSNESTEDMESSAGE_B163._serialized_end=1931 - _LOTSNESTEDMESSAGE_B164._serialized_start=1933 - _LOTSNESTEDMESSAGE_B164._serialized_end=1939 - _LOTSNESTEDMESSAGE_B165._serialized_start=1941 - _LOTSNESTEDMESSAGE_B165._serialized_end=1947 - _LOTSNESTEDMESSAGE_B166._serialized_start=1949 - _LOTSNESTEDMESSAGE_B166._serialized_end=1955 - _LOTSNESTEDMESSAGE_B167._serialized_start=1957 - _LOTSNESTEDMESSAGE_B167._serialized_end=1963 - _LOTSNESTEDMESSAGE_B168._serialized_start=1965 - _LOTSNESTEDMESSAGE_B168._serialized_end=1971 - _LOTSNESTEDMESSAGE_B169._serialized_start=1973 - _LOTSNESTEDMESSAGE_B169._serialized_end=1979 - _LOTSNESTEDMESSAGE_B170._serialized_start=1981 - _LOTSNESTEDMESSAGE_B170._serialized_end=1987 - _LOTSNESTEDMESSAGE_B171._serialized_start=1989 - _LOTSNESTEDMESSAGE_B171._serialized_end=1995 - _LOTSNESTEDMESSAGE_B172._serialized_start=1997 - _LOTSNESTEDMESSAGE_B172._serialized_end=2003 - _LOTSNESTEDMESSAGE_B173._serialized_start=2005 - _LOTSNESTEDMESSAGE_B173._serialized_end=2011 - _LOTSNESTEDMESSAGE_B174._serialized_start=2013 - _LOTSNESTEDMESSAGE_B174._serialized_end=2019 - _LOTSNESTEDMESSAGE_B175._serialized_start=2021 - _LOTSNESTEDMESSAGE_B175._serialized_end=2027 - _LOTSNESTEDMESSAGE_B176._serialized_start=2029 - _LOTSNESTEDMESSAGE_B176._serialized_end=2035 - _LOTSNESTEDMESSAGE_B177._serialized_start=2037 - _LOTSNESTEDMESSAGE_B177._serialized_end=2043 - _LOTSNESTEDMESSAGE_B178._serialized_start=2045 - _LOTSNESTEDMESSAGE_B178._serialized_end=2051 - _LOTSNESTEDMESSAGE_B179._serialized_start=2053 - _LOTSNESTEDMESSAGE_B179._serialized_end=2059 - _LOTSNESTEDMESSAGE_B180._serialized_start=2061 - _LOTSNESTEDMESSAGE_B180._serialized_end=2067 - _LOTSNESTEDMESSAGE_B181._serialized_start=2069 - _LOTSNESTEDMESSAGE_B181._serialized_end=2075 - _LOTSNESTEDMESSAGE_B182._serialized_start=2077 - _LOTSNESTEDMESSAGE_B182._serialized_end=2083 - _LOTSNESTEDMESSAGE_B183._serialized_start=2085 - _LOTSNESTEDMESSAGE_B183._serialized_end=2091 - _LOTSNESTEDMESSAGE_B184._serialized_start=2093 - _LOTSNESTEDMESSAGE_B184._serialized_end=2099 - _LOTSNESTEDMESSAGE_B185._serialized_start=2101 - _LOTSNESTEDMESSAGE_B185._serialized_end=2107 - _LOTSNESTEDMESSAGE_B186._serialized_start=2109 - _LOTSNESTEDMESSAGE_B186._serialized_end=2115 - _LOTSNESTEDMESSAGE_B187._serialized_start=2117 - _LOTSNESTEDMESSAGE_B187._serialized_end=2123 - _LOTSNESTEDMESSAGE_B188._serialized_start=2125 - _LOTSNESTEDMESSAGE_B188._serialized_end=2131 - _LOTSNESTEDMESSAGE_B189._serialized_start=2133 - _LOTSNESTEDMESSAGE_B189._serialized_end=2139 - _LOTSNESTEDMESSAGE_B190._serialized_start=2141 - _LOTSNESTEDMESSAGE_B190._serialized_end=2147 - _LOTSNESTEDMESSAGE_B191._serialized_start=2149 - _LOTSNESTEDMESSAGE_B191._serialized_end=2155 - _LOTSNESTEDMESSAGE_B192._serialized_start=2157 - _LOTSNESTEDMESSAGE_B192._serialized_end=2163 - _LOTSNESTEDMESSAGE_B193._serialized_start=2165 - _LOTSNESTEDMESSAGE_B193._serialized_end=2171 - _LOTSNESTEDMESSAGE_B194._serialized_start=2173 - _LOTSNESTEDMESSAGE_B194._serialized_end=2179 - _LOTSNESTEDMESSAGE_B195._serialized_start=2181 - _LOTSNESTEDMESSAGE_B195._serialized_end=2187 - _LOTSNESTEDMESSAGE_B196._serialized_start=2189 - _LOTSNESTEDMESSAGE_B196._serialized_end=2195 - _LOTSNESTEDMESSAGE_B197._serialized_start=2197 - _LOTSNESTEDMESSAGE_B197._serialized_end=2203 - _LOTSNESTEDMESSAGE_B198._serialized_start=2205 - _LOTSNESTEDMESSAGE_B198._serialized_end=2211 - _LOTSNESTEDMESSAGE_B199._serialized_start=2213 - _LOTSNESTEDMESSAGE_B199._serialized_end=2219 - _LOTSNESTEDMESSAGE_B200._serialized_start=2221 - _LOTSNESTEDMESSAGE_B200._serialized_end=2227 - _LOTSNESTEDMESSAGE_B201._serialized_start=2229 - _LOTSNESTEDMESSAGE_B201._serialized_end=2235 - _LOTSNESTEDMESSAGE_B202._serialized_start=2237 - _LOTSNESTEDMESSAGE_B202._serialized_end=2243 - _LOTSNESTEDMESSAGE_B203._serialized_start=2245 - _LOTSNESTEDMESSAGE_B203._serialized_end=2251 - _LOTSNESTEDMESSAGE_B204._serialized_start=2253 - _LOTSNESTEDMESSAGE_B204._serialized_end=2259 - _LOTSNESTEDMESSAGE_B205._serialized_start=2261 - _LOTSNESTEDMESSAGE_B205._serialized_end=2267 - _LOTSNESTEDMESSAGE_B206._serialized_start=2269 - _LOTSNESTEDMESSAGE_B206._serialized_end=2275 - _LOTSNESTEDMESSAGE_B207._serialized_start=2277 - _LOTSNESTEDMESSAGE_B207._serialized_end=2283 - _LOTSNESTEDMESSAGE_B208._serialized_start=2285 - _LOTSNESTEDMESSAGE_B208._serialized_end=2291 - _LOTSNESTEDMESSAGE_B209._serialized_start=2293 - _LOTSNESTEDMESSAGE_B209._serialized_end=2299 - _LOTSNESTEDMESSAGE_B210._serialized_start=2301 - _LOTSNESTEDMESSAGE_B210._serialized_end=2307 - _LOTSNESTEDMESSAGE_B211._serialized_start=2309 - _LOTSNESTEDMESSAGE_B211._serialized_end=2315 - _LOTSNESTEDMESSAGE_B212._serialized_start=2317 - _LOTSNESTEDMESSAGE_B212._serialized_end=2323 - _LOTSNESTEDMESSAGE_B213._serialized_start=2325 - _LOTSNESTEDMESSAGE_B213._serialized_end=2331 - _LOTSNESTEDMESSAGE_B214._serialized_start=2333 - _LOTSNESTEDMESSAGE_B214._serialized_end=2339 - _LOTSNESTEDMESSAGE_B215._serialized_start=2341 - _LOTSNESTEDMESSAGE_B215._serialized_end=2347 - _LOTSNESTEDMESSAGE_B216._serialized_start=2349 - _LOTSNESTEDMESSAGE_B216._serialized_end=2355 - _LOTSNESTEDMESSAGE_B217._serialized_start=2357 - _LOTSNESTEDMESSAGE_B217._serialized_end=2363 - _LOTSNESTEDMESSAGE_B218._serialized_start=2365 - _LOTSNESTEDMESSAGE_B218._serialized_end=2371 - _LOTSNESTEDMESSAGE_B219._serialized_start=2373 - _LOTSNESTEDMESSAGE_B219._serialized_end=2379 - _LOTSNESTEDMESSAGE_B220._serialized_start=2381 - _LOTSNESTEDMESSAGE_B220._serialized_end=2387 - _LOTSNESTEDMESSAGE_B221._serialized_start=2389 - _LOTSNESTEDMESSAGE_B221._serialized_end=2395 - _LOTSNESTEDMESSAGE_B222._serialized_start=2397 - _LOTSNESTEDMESSAGE_B222._serialized_end=2403 - _LOTSNESTEDMESSAGE_B223._serialized_start=2405 - _LOTSNESTEDMESSAGE_B223._serialized_end=2411 - _LOTSNESTEDMESSAGE_B224._serialized_start=2413 - _LOTSNESTEDMESSAGE_B224._serialized_end=2419 - _LOTSNESTEDMESSAGE_B225._serialized_start=2421 - _LOTSNESTEDMESSAGE_B225._serialized_end=2427 - _LOTSNESTEDMESSAGE_B226._serialized_start=2429 - _LOTSNESTEDMESSAGE_B226._serialized_end=2435 - _LOTSNESTEDMESSAGE_B227._serialized_start=2437 - _LOTSNESTEDMESSAGE_B227._serialized_end=2443 - _LOTSNESTEDMESSAGE_B228._serialized_start=2445 - _LOTSNESTEDMESSAGE_B228._serialized_end=2451 - _LOTSNESTEDMESSAGE_B229._serialized_start=2453 - _LOTSNESTEDMESSAGE_B229._serialized_end=2459 - _LOTSNESTEDMESSAGE_B230._serialized_start=2461 - _LOTSNESTEDMESSAGE_B230._serialized_end=2467 - _LOTSNESTEDMESSAGE_B231._serialized_start=2469 - _LOTSNESTEDMESSAGE_B231._serialized_end=2475 - _LOTSNESTEDMESSAGE_B232._serialized_start=2477 - _LOTSNESTEDMESSAGE_B232._serialized_end=2483 - _LOTSNESTEDMESSAGE_B233._serialized_start=2485 - _LOTSNESTEDMESSAGE_B233._serialized_end=2491 - _LOTSNESTEDMESSAGE_B234._serialized_start=2493 - _LOTSNESTEDMESSAGE_B234._serialized_end=2499 - _LOTSNESTEDMESSAGE_B235._serialized_start=2501 - _LOTSNESTEDMESSAGE_B235._serialized_end=2507 - _LOTSNESTEDMESSAGE_B236._serialized_start=2509 - _LOTSNESTEDMESSAGE_B236._serialized_end=2515 - _LOTSNESTEDMESSAGE_B237._serialized_start=2517 - _LOTSNESTEDMESSAGE_B237._serialized_end=2523 - _LOTSNESTEDMESSAGE_B238._serialized_start=2525 - _LOTSNESTEDMESSAGE_B238._serialized_end=2531 - _LOTSNESTEDMESSAGE_B239._serialized_start=2533 - _LOTSNESTEDMESSAGE_B239._serialized_end=2539 - _LOTSNESTEDMESSAGE_B240._serialized_start=2541 - _LOTSNESTEDMESSAGE_B240._serialized_end=2547 - _LOTSNESTEDMESSAGE_B241._serialized_start=2549 - _LOTSNESTEDMESSAGE_B241._serialized_end=2555 - _LOTSNESTEDMESSAGE_B242._serialized_start=2557 - _LOTSNESTEDMESSAGE_B242._serialized_end=2563 - _LOTSNESTEDMESSAGE_B243._serialized_start=2565 - _LOTSNESTEDMESSAGE_B243._serialized_end=2571 - _LOTSNESTEDMESSAGE_B244._serialized_start=2573 - _LOTSNESTEDMESSAGE_B244._serialized_end=2579 - _LOTSNESTEDMESSAGE_B245._serialized_start=2581 - _LOTSNESTEDMESSAGE_B245._serialized_end=2587 - _LOTSNESTEDMESSAGE_B246._serialized_start=2589 - _LOTSNESTEDMESSAGE_B246._serialized_end=2595 - _LOTSNESTEDMESSAGE_B247._serialized_start=2597 - _LOTSNESTEDMESSAGE_B247._serialized_end=2603 - _LOTSNESTEDMESSAGE_B248._serialized_start=2605 - _LOTSNESTEDMESSAGE_B248._serialized_end=2611 - _LOTSNESTEDMESSAGE_B249._serialized_start=2613 - _LOTSNESTEDMESSAGE_B249._serialized_end=2619 - _LOTSNESTEDMESSAGE_B250._serialized_start=2621 - _LOTSNESTEDMESSAGE_B250._serialized_end=2627 - _LOTSNESTEDMESSAGE_B251._serialized_start=2629 - _LOTSNESTEDMESSAGE_B251._serialized_end=2635 - _LOTSNESTEDMESSAGE_B252._serialized_start=2637 - _LOTSNESTEDMESSAGE_B252._serialized_end=2643 - _LOTSNESTEDMESSAGE_B253._serialized_start=2645 - _LOTSNESTEDMESSAGE_B253._serialized_end=2651 - _LOTSNESTEDMESSAGE_B254._serialized_start=2653 - _LOTSNESTEDMESSAGE_B254._serialized_end=2659 - _LOTSNESTEDMESSAGE_B255._serialized_start=2661 - _LOTSNESTEDMESSAGE_B255._serialized_end=2667 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/internal/no_package_pb2.py b/scripts/protobuf3/protobuf3/internal/no_package_pb2.py deleted file mode 100644 index d46dee0..0000000 --- a/scripts/protobuf3/protobuf3/internal/no_package_pb2.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/internal/no_package.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n)google/protobuf/internal/no_package.proto\";\n\x10NoPackageMessage\x12\'\n\x0fno_package_enum\x18\x01 \x01(\x0e\x32\x0e.NoPackageEnum*?\n\rNoPackageEnum\x12\x16\n\x12NO_PACKAGE_VALUE_0\x10\x00\x12\x16\n\x12NO_PACKAGE_VALUE_1\x10\x01') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.internal.no_package_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _NOPACKAGEENUM._serialized_start=106 - _NOPACKAGEENUM._serialized_end=169 - _NOPACKAGEMESSAGE._serialized_start=45 - _NOPACKAGEMESSAGE._serialized_end=104 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/internal/python_message.py b/scripts/protobuf3/protobuf3/internal/python_message.py deleted file mode 100644 index 2921d5c..0000000 --- a/scripts/protobuf3/protobuf3/internal/python_message.py +++ /dev/null @@ -1,1539 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# This code is meant to work on Python 2.4 and above only. -# -# TODO(robinson): Helpers for verbose, common checks like seeing if a -# descriptor's cpp_type is CPPTYPE_MESSAGE. - -"""Contains a metaclass and helper functions used to create -protocol message classes from Descriptor objects at runtime. - -Recall that a metaclass is the "type" of a class. -(A class is to a metaclass what an instance is to a class.) - -In this case, we use the GeneratedProtocolMessageType metaclass -to inject all the useful functionality into the classes -output by the protocol compiler at compile-time. - -The upshot of all this is that the real implementation -details for ALL pure-Python protocol buffers are *here in -this file*. -""" - -__author__ = 'robinson@google.com (Will Robinson)' - -from io import BytesIO -import struct -import sys -import weakref - -# We use "as" to avoid name collisions with variables. -from google.protobuf.internal import api_implementation -from google.protobuf.internal import containers -from google.protobuf.internal import decoder -from google.protobuf.internal import encoder -from google.protobuf.internal import enum_type_wrapper -from google.protobuf.internal import extension_dict -from google.protobuf.internal import message_listener as message_listener_mod -from google.protobuf.internal import type_checkers -from google.protobuf.internal import well_known_types -from google.protobuf.internal import wire_format -from google.protobuf import descriptor as descriptor_mod -from google.protobuf import message as message_mod -from google.protobuf import text_format - -_FieldDescriptor = descriptor_mod.FieldDescriptor -_AnyFullTypeName = 'google.protobuf.Any' -_ExtensionDict = extension_dict._ExtensionDict - -class GeneratedProtocolMessageType(type): - - """Metaclass for protocol message classes created at runtime from Descriptors. - - We add implementations for all methods described in the Message class. We - also create properties to allow getting/setting all fields in the protocol - message. Finally, we create slots to prevent users from accidentally - "setting" nonexistent fields in the protocol message, which then wouldn't get - serialized / deserialized properly. - - The protocol compiler currently uses this metaclass to create protocol - message classes at runtime. Clients can also manually create their own - classes at runtime, as in this example: - - mydescriptor = Descriptor(.....) - factory = symbol_database.Default() - factory.pool.AddDescriptor(mydescriptor) - MyProtoClass = factory.GetPrototype(mydescriptor) - myproto_instance = MyProtoClass() - myproto.foo_field = 23 - ... - """ - - # Must be consistent with the protocol-compiler code in - # proto2/compiler/internal/generator.*. - _DESCRIPTOR_KEY = 'DESCRIPTOR' - - def __new__(cls, name, bases, dictionary): - """Custom allocation for runtime-generated class types. - - We override __new__ because this is apparently the only place - where we can meaningfully set __slots__ on the class we're creating(?). - (The interplay between metaclasses and slots is not very well-documented). - - Args: - name: Name of the class (ignored, but required by the - metaclass protocol). - bases: Base classes of the class we're constructing. - (Should be message.Message). We ignore this field, but - it's required by the metaclass protocol - dictionary: The class dictionary of the class we're - constructing. dictionary[_DESCRIPTOR_KEY] must contain - a Descriptor object describing this protocol message - type. - - Returns: - Newly-allocated class. - - Raises: - RuntimeError: Generated code only work with python cpp extension. - """ - descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] - - if isinstance(descriptor, str): - raise RuntimeError('The generated code only work with python cpp ' - 'extension, but it is using pure python runtime.') - - # If a concrete class already exists for this descriptor, don't try to - # create another. Doing so will break any messages that already exist with - # the existing class. - # - # The C++ implementation appears to have its own internal `PyMessageFactory` - # to achieve similar results. - # - # This most commonly happens in `text_format.py` when using descriptors from - # a custom pool; it calls symbol_database.Global().getPrototype() on a - # descriptor which already has an existing concrete class. - new_class = getattr(descriptor, '_concrete_class', None) - if new_class: - return new_class - - if descriptor.full_name in well_known_types.WKTBASES: - bases += (well_known_types.WKTBASES[descriptor.full_name],) - _AddClassAttributesForNestedExtensions(descriptor, dictionary) - _AddSlots(descriptor, dictionary) - - superclass = super(GeneratedProtocolMessageType, cls) - new_class = superclass.__new__(cls, name, bases, dictionary) - return new_class - - def __init__(cls, name, bases, dictionary): - """Here we perform the majority of our work on the class. - We add enum getters, an __init__ method, implementations - of all Message methods, and properties for all fields - in the protocol type. - - Args: - name: Name of the class (ignored, but required by the - metaclass protocol). - bases: Base classes of the class we're constructing. - (Should be message.Message). We ignore this field, but - it's required by the metaclass protocol - dictionary: The class dictionary of the class we're - constructing. dictionary[_DESCRIPTOR_KEY] must contain - a Descriptor object describing this protocol message - type. - """ - descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] - - # If this is an _existing_ class looked up via `_concrete_class` in the - # __new__ method above, then we don't need to re-initialize anything. - existing_class = getattr(descriptor, '_concrete_class', None) - if existing_class: - assert existing_class is cls, ( - 'Duplicate `GeneratedProtocolMessageType` created for descriptor %r' - % (descriptor.full_name)) - return - - cls._decoders_by_tag = {} - if (descriptor.has_options and - descriptor.GetOptions().message_set_wire_format): - cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( - decoder.MessageSetItemDecoder(descriptor), None) - - # Attach stuff to each FieldDescriptor for quick lookup later on. - for field in descriptor.fields: - _AttachFieldHelpers(cls, field) - - descriptor._concrete_class = cls # pylint: disable=protected-access - _AddEnumValues(descriptor, cls) - _AddInitMethod(descriptor, cls) - _AddPropertiesForFields(descriptor, cls) - _AddPropertiesForExtensions(descriptor, cls) - _AddStaticMethods(cls) - _AddMessageMethods(descriptor, cls) - _AddPrivateHelperMethods(descriptor, cls) - - superclass = super(GeneratedProtocolMessageType, cls) - superclass.__init__(name, bases, dictionary) - - -# Stateless helpers for GeneratedProtocolMessageType below. -# Outside clients should not access these directly. -# -# I opted not to make any of these methods on the metaclass, to make it more -# clear that I'm not really using any state there and to keep clients from -# thinking that they have direct access to these construction helpers. - - -def _PropertyName(proto_field_name): - """Returns the name of the public property attribute which - clients can use to get and (in some cases) set the value - of a protocol message field. - - Args: - proto_field_name: The protocol message field name, exactly - as it appears (or would appear) in a .proto file. - """ - # TODO(robinson): Escape Python keywords (e.g., yield), and test this support. - # nnorwitz makes my day by writing: - # """ - # FYI. See the keyword module in the stdlib. This could be as simple as: - # - # if keyword.iskeyword(proto_field_name): - # return proto_field_name + "_" - # return proto_field_name - # """ - # Kenton says: The above is a BAD IDEA. People rely on being able to use - # getattr() and setattr() to reflectively manipulate field values. If we - # rename the properties, then every such user has to also make sure to apply - # the same transformation. Note that currently if you name a field "yield", - # you can still access it just fine using getattr/setattr -- it's not even - # that cumbersome to do so. - # TODO(kenton): Remove this method entirely if/when everyone agrees with my - # position. - return proto_field_name - - -def _AddSlots(message_descriptor, dictionary): - """Adds a __slots__ entry to dictionary, containing the names of all valid - attributes for this message type. - - Args: - message_descriptor: A Descriptor instance describing this message type. - dictionary: Class dictionary to which we'll add a '__slots__' entry. - """ - dictionary['__slots__'] = ['_cached_byte_size', - '_cached_byte_size_dirty', - '_fields', - '_unknown_fields', - '_unknown_field_set', - '_is_present_in_parent', - '_listener', - '_listener_for_children', - '__weakref__', - '_oneofs'] - - -def _IsMessageSetExtension(field): - return (field.is_extension and - field.containing_type.has_options and - field.containing_type.GetOptions().message_set_wire_format and - field.type == _FieldDescriptor.TYPE_MESSAGE and - field.label == _FieldDescriptor.LABEL_OPTIONAL) - - -def _IsMapField(field): - return (field.type == _FieldDescriptor.TYPE_MESSAGE and - field.message_type.has_options and - field.message_type.GetOptions().map_entry) - - -def _IsMessageMapField(field): - value_type = field.message_type.fields_by_name['value'] - return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE - - -def _AttachFieldHelpers(cls, field_descriptor): - is_repeated = (field_descriptor.label == _FieldDescriptor.LABEL_REPEATED) - is_packable = (is_repeated and - wire_format.IsTypePackable(field_descriptor.type)) - is_proto3 = field_descriptor.containing_type.syntax == 'proto3' - if not is_packable: - is_packed = False - elif field_descriptor.containing_type.syntax == 'proto2': - is_packed = (field_descriptor.has_options and - field_descriptor.GetOptions().packed) - else: - has_packed_false = (field_descriptor.has_options and - field_descriptor.GetOptions().HasField('packed') and - field_descriptor.GetOptions().packed == False) - is_packed = not has_packed_false - is_map_entry = _IsMapField(field_descriptor) - - if is_map_entry: - field_encoder = encoder.MapEncoder(field_descriptor) - sizer = encoder.MapSizer(field_descriptor, - _IsMessageMapField(field_descriptor)) - elif _IsMessageSetExtension(field_descriptor): - field_encoder = encoder.MessageSetItemEncoder(field_descriptor.number) - sizer = encoder.MessageSetItemSizer(field_descriptor.number) - else: - field_encoder = type_checkers.TYPE_TO_ENCODER[field_descriptor.type]( - field_descriptor.number, is_repeated, is_packed) - sizer = type_checkers.TYPE_TO_SIZER[field_descriptor.type]( - field_descriptor.number, is_repeated, is_packed) - - field_descriptor._encoder = field_encoder - field_descriptor._sizer = sizer - field_descriptor._default_constructor = _DefaultValueConstructorForField( - field_descriptor) - - def AddDecoder(wiretype, is_packed): - tag_bytes = encoder.TagBytes(field_descriptor.number, wiretype) - decode_type = field_descriptor.type - if (decode_type == _FieldDescriptor.TYPE_ENUM and - type_checkers.SupportsOpenEnums(field_descriptor)): - decode_type = _FieldDescriptor.TYPE_INT32 - - oneof_descriptor = None - clear_if_default = False - if field_descriptor.containing_oneof is not None: - oneof_descriptor = field_descriptor - elif (is_proto3 and not is_repeated and - field_descriptor.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE): - clear_if_default = True - - if is_map_entry: - is_message_map = _IsMessageMapField(field_descriptor) - - field_decoder = decoder.MapDecoder( - field_descriptor, _GetInitializeDefaultForMap(field_descriptor), - is_message_map) - elif decode_type == _FieldDescriptor.TYPE_STRING: - field_decoder = decoder.StringDecoder( - field_descriptor.number, is_repeated, is_packed, - field_descriptor, field_descriptor._default_constructor, - clear_if_default) - elif field_descriptor.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - field_decoder = type_checkers.TYPE_TO_DECODER[decode_type]( - field_descriptor.number, is_repeated, is_packed, - field_descriptor, field_descriptor._default_constructor) - else: - field_decoder = type_checkers.TYPE_TO_DECODER[decode_type]( - field_descriptor.number, is_repeated, is_packed, - # pylint: disable=protected-access - field_descriptor, field_descriptor._default_constructor, - clear_if_default) - - cls._decoders_by_tag[tag_bytes] = (field_decoder, oneof_descriptor) - - AddDecoder(type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type], - False) - - if is_repeated and wire_format.IsTypePackable(field_descriptor.type): - # To support wire compatibility of adding packed = true, add a decoder for - # packed values regardless of the field's options. - AddDecoder(wire_format.WIRETYPE_LENGTH_DELIMITED, True) - - -def _AddClassAttributesForNestedExtensions(descriptor, dictionary): - extensions = descriptor.extensions_by_name - for extension_name, extension_field in extensions.items(): - assert extension_name not in dictionary - dictionary[extension_name] = extension_field - - -def _AddEnumValues(descriptor, cls): - """Sets class-level attributes for all enum fields defined in this message. - - Also exporting a class-level object that can name enum values. - - Args: - descriptor: Descriptor object for this message type. - cls: Class we're constructing for this message type. - """ - for enum_type in descriptor.enum_types: - setattr(cls, enum_type.name, enum_type_wrapper.EnumTypeWrapper(enum_type)) - for enum_value in enum_type.values: - setattr(cls, enum_value.name, enum_value.number) - - -def _GetInitializeDefaultForMap(field): - if field.label != _FieldDescriptor.LABEL_REPEATED: - raise ValueError('map_entry set on non-repeated field %s' % ( - field.name)) - fields_by_name = field.message_type.fields_by_name - key_checker = type_checkers.GetTypeChecker(fields_by_name['key']) - - value_field = fields_by_name['value'] - if _IsMessageMapField(field): - def MakeMessageMapDefault(message): - return containers.MessageMap( - message._listener_for_children, value_field.message_type, key_checker, - field.message_type) - return MakeMessageMapDefault - else: - value_checker = type_checkers.GetTypeChecker(value_field) - def MakePrimitiveMapDefault(message): - return containers.ScalarMap( - message._listener_for_children, key_checker, value_checker, - field.message_type) - return MakePrimitiveMapDefault - -def _DefaultValueConstructorForField(field): - """Returns a function which returns a default value for a field. - - Args: - field: FieldDescriptor object for this field. - - The returned function has one argument: - message: Message instance containing this field, or a weakref proxy - of same. - - That function in turn returns a default value for this field. The default - value may refer back to |message| via a weak reference. - """ - - if _IsMapField(field): - return _GetInitializeDefaultForMap(field) - - if field.label == _FieldDescriptor.LABEL_REPEATED: - if field.has_default_value and field.default_value != []: - raise ValueError('Repeated field default value not empty list: %s' % ( - field.default_value)) - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - # We can't look at _concrete_class yet since it might not have - # been set. (Depends on order in which we initialize the classes). - message_type = field.message_type - def MakeRepeatedMessageDefault(message): - return containers.RepeatedCompositeFieldContainer( - message._listener_for_children, field.message_type) - return MakeRepeatedMessageDefault - else: - type_checker = type_checkers.GetTypeChecker(field) - def MakeRepeatedScalarDefault(message): - return containers.RepeatedScalarFieldContainer( - message._listener_for_children, type_checker) - return MakeRepeatedScalarDefault - - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - # _concrete_class may not yet be initialized. - message_type = field.message_type - def MakeSubMessageDefault(message): - assert getattr(message_type, '_concrete_class', None), ( - 'Uninitialized concrete class found for field %r (message type %r)' - % (field.full_name, message_type.full_name)) - result = message_type._concrete_class() - result._SetListener( - _OneofListener(message, field) - if field.containing_oneof is not None - else message._listener_for_children) - return result - return MakeSubMessageDefault - - def MakeScalarDefault(message): - # TODO(protobuf-team): This may be broken since there may not be - # default_value. Combine with has_default_value somehow. - return field.default_value - return MakeScalarDefault - - -def _ReraiseTypeErrorWithFieldName(message_name, field_name): - """Re-raise the currently-handled TypeError with the field name added.""" - exc = sys.exc_info()[1] - if len(exc.args) == 1 and type(exc) is TypeError: - # simple TypeError; add field name to exception message - exc = TypeError('%s for field %s.%s' % (str(exc), message_name, field_name)) - - # re-raise possibly-amended exception with original traceback: - raise exc.with_traceback(sys.exc_info()[2]) - - -def _AddInitMethod(message_descriptor, cls): - """Adds an __init__ method to cls.""" - - def _GetIntegerEnumValue(enum_type, value): - """Convert a string or integer enum value to an integer. - - If the value is a string, it is converted to the enum value in - enum_type with the same name. If the value is not a string, it's - returned as-is. (No conversion or bounds-checking is done.) - """ - if isinstance(value, str): - try: - return enum_type.values_by_name[value].number - except KeyError: - raise ValueError('Enum type %s: unknown label "%s"' % ( - enum_type.full_name, value)) - return value - - def init(self, **kwargs): - self._cached_byte_size = 0 - self._cached_byte_size_dirty = len(kwargs) > 0 - self._fields = {} - # Contains a mapping from oneof field descriptors to the descriptor - # of the currently set field in that oneof field. - self._oneofs = {} - - # _unknown_fields is () when empty for efficiency, and will be turned into - # a list if fields are added. - self._unknown_fields = () - # _unknown_field_set is None when empty for efficiency, and will be - # turned into UnknownFieldSet struct if fields are added. - self._unknown_field_set = None # pylint: disable=protected-access - self._is_present_in_parent = False - self._listener = message_listener_mod.NullMessageListener() - self._listener_for_children = _Listener(self) - for field_name, field_value in kwargs.items(): - field = _GetFieldByName(message_descriptor, field_name) - if field is None: - raise TypeError('%s() got an unexpected keyword argument "%s"' % - (message_descriptor.name, field_name)) - if field_value is None: - # field=None is the same as no field at all. - continue - if field.label == _FieldDescriptor.LABEL_REPEATED: - copy = field._default_constructor(self) - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: # Composite - if _IsMapField(field): - if _IsMessageMapField(field): - for key in field_value: - copy[key].MergeFrom(field_value[key]) - else: - copy.update(field_value) - else: - for val in field_value: - if isinstance(val, dict): - copy.add(**val) - else: - copy.add().MergeFrom(val) - else: # Scalar - if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM: - field_value = [_GetIntegerEnumValue(field.enum_type, val) - for val in field_value] - copy.extend(field_value) - self._fields[field] = copy - elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - copy = field._default_constructor(self) - new_val = field_value - if isinstance(field_value, dict): - new_val = field.message_type._concrete_class(**field_value) - try: - copy.MergeFrom(new_val) - except TypeError: - _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name) - self._fields[field] = copy - else: - if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM: - field_value = _GetIntegerEnumValue(field.enum_type, field_value) - try: - setattr(self, field_name, field_value) - except TypeError: - _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name) - - init.__module__ = None - init.__doc__ = None - cls.__init__ = init - - -def _GetFieldByName(message_descriptor, field_name): - """Returns a field descriptor by field name. - - Args: - message_descriptor: A Descriptor describing all fields in message. - field_name: The name of the field to retrieve. - Returns: - The field descriptor associated with the field name. - """ - try: - return message_descriptor.fields_by_name[field_name] - except KeyError: - raise ValueError('Protocol message %s has no "%s" field.' % - (message_descriptor.name, field_name)) - - -def _AddPropertiesForFields(descriptor, cls): - """Adds properties for all fields in this protocol message type.""" - for field in descriptor.fields: - _AddPropertiesForField(field, cls) - - if descriptor.is_extendable: - # _ExtensionDict is just an adaptor with no state so we allocate a new one - # every time it is accessed. - cls.Extensions = property(lambda self: _ExtensionDict(self)) - - -def _AddPropertiesForField(field, cls): - """Adds a public property for a protocol message field. - Clients can use this property to get and (in the case - of non-repeated scalar fields) directly set the value - of a protocol message field. - - Args: - field: A FieldDescriptor for this field. - cls: The class we're constructing. - """ - # Catch it if we add other types that we should - # handle specially here. - assert _FieldDescriptor.MAX_CPPTYPE == 10 - - constant_name = field.name.upper() + '_FIELD_NUMBER' - setattr(cls, constant_name, field.number) - - if field.label == _FieldDescriptor.LABEL_REPEATED: - _AddPropertiesForRepeatedField(field, cls) - elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - _AddPropertiesForNonRepeatedCompositeField(field, cls) - else: - _AddPropertiesForNonRepeatedScalarField(field, cls) - - -class _FieldProperty(property): - __slots__ = ('DESCRIPTOR',) - - def __init__(self, descriptor, getter, setter, doc): - property.__init__(self, getter, setter, doc=doc) - self.DESCRIPTOR = descriptor - - -def _AddPropertiesForRepeatedField(field, cls): - """Adds a public property for a "repeated" protocol message field. Clients - can use this property to get the value of the field, which will be either a - RepeatedScalarFieldContainer or RepeatedCompositeFieldContainer (see - below). - - Note that when clients add values to these containers, we perform - type-checking in the case of repeated scalar fields, and we also set any - necessary "has" bits as a side-effect. - - Args: - field: A FieldDescriptor for this field. - cls: The class we're constructing. - """ - proto_field_name = field.name - property_name = _PropertyName(proto_field_name) - - def getter(self): - field_value = self._fields.get(field) - if field_value is None: - # Construct a new object to represent this field. - field_value = field._default_constructor(self) - - # Atomically check if another thread has preempted us and, if not, swap - # in the new object we just created. If someone has preempted us, we - # take that object and discard ours. - # WARNING: We are relying on setdefault() being atomic. This is true - # in CPython but we haven't investigated others. This warning appears - # in several other locations in this file. - field_value = self._fields.setdefault(field, field_value) - return field_value - getter.__module__ = None - getter.__doc__ = 'Getter for %s.' % proto_field_name - - # We define a setter just so we can throw an exception with a more - # helpful error message. - def setter(self, new_value): - raise AttributeError('Assignment not allowed to repeated field ' - '"%s" in protocol message object.' % proto_field_name) - - doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name - setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc)) - - -def _AddPropertiesForNonRepeatedScalarField(field, cls): - """Adds a public property for a nonrepeated, scalar protocol message field. - Clients can use this property to get and directly set the value of the field. - Note that when the client sets the value of a field by using this property, - all necessary "has" bits are set as a side-effect, and we also perform - type-checking. - - Args: - field: A FieldDescriptor for this field. - cls: The class we're constructing. - """ - proto_field_name = field.name - property_name = _PropertyName(proto_field_name) - type_checker = type_checkers.GetTypeChecker(field) - default_value = field.default_value - is_proto3 = field.containing_type.syntax == 'proto3' - - def getter(self): - # TODO(protobuf-team): This may be broken since there may not be - # default_value. Combine with has_default_value somehow. - return self._fields.get(field, default_value) - getter.__module__ = None - getter.__doc__ = 'Getter for %s.' % proto_field_name - - clear_when_set_to_default = is_proto3 and not field.containing_oneof - - def field_setter(self, new_value): - # pylint: disable=protected-access - # Testing the value for truthiness captures all of the proto3 defaults - # (0, 0.0, enum 0, and False). - try: - new_value = type_checker.CheckValue(new_value) - except TypeError as e: - raise TypeError( - 'Cannot set %s to %.1024r: %s' % (field.full_name, new_value, e)) - if clear_when_set_to_default and not new_value: - self._fields.pop(field, None) - else: - self._fields[field] = new_value - # Check _cached_byte_size_dirty inline to improve performance, since scalar - # setters are called frequently. - if not self._cached_byte_size_dirty: - self._Modified() - - if field.containing_oneof: - def setter(self, new_value): - field_setter(self, new_value) - self._UpdateOneofState(field) - else: - setter = field_setter - - setter.__module__ = None - setter.__doc__ = 'Setter for %s.' % proto_field_name - - # Add a property to encapsulate the getter/setter. - doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name - setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc)) - - -def _AddPropertiesForNonRepeatedCompositeField(field, cls): - """Adds a public property for a nonrepeated, composite protocol message field. - A composite field is a "group" or "message" field. - - Clients can use this property to get the value of the field, but cannot - assign to the property directly. - - Args: - field: A FieldDescriptor for this field. - cls: The class we're constructing. - """ - # TODO(robinson): Remove duplication with similar method - # for non-repeated scalars. - proto_field_name = field.name - property_name = _PropertyName(proto_field_name) - - def getter(self): - field_value = self._fields.get(field) - if field_value is None: - # Construct a new object to represent this field. - field_value = field._default_constructor(self) - - # Atomically check if another thread has preempted us and, if not, swap - # in the new object we just created. If someone has preempted us, we - # take that object and discard ours. - # WARNING: We are relying on setdefault() being atomic. This is true - # in CPython but we haven't investigated others. This warning appears - # in several other locations in this file. - field_value = self._fields.setdefault(field, field_value) - return field_value - getter.__module__ = None - getter.__doc__ = 'Getter for %s.' % proto_field_name - - # We define a setter just so we can throw an exception with a more - # helpful error message. - def setter(self, new_value): - raise AttributeError('Assignment not allowed to composite field ' - '"%s" in protocol message object.' % proto_field_name) - - # Add a property to encapsulate the getter. - doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name - setattr(cls, property_name, _FieldProperty(field, getter, setter, doc=doc)) - - -def _AddPropertiesForExtensions(descriptor, cls): - """Adds properties for all fields in this protocol message type.""" - extensions = descriptor.extensions_by_name - for extension_name, extension_field in extensions.items(): - constant_name = extension_name.upper() + '_FIELD_NUMBER' - setattr(cls, constant_name, extension_field.number) - - # TODO(amauryfa): Migrate all users of these attributes to functions like - # pool.FindExtensionByNumber(descriptor). - if descriptor.file is not None: - # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available. - pool = descriptor.file.pool - cls._extensions_by_number = pool._extensions_by_number[descriptor] - cls._extensions_by_name = pool._extensions_by_name[descriptor] - -def _AddStaticMethods(cls): - # TODO(robinson): This probably needs to be thread-safe(?) - def RegisterExtension(extension_handle): - extension_handle.containing_type = cls.DESCRIPTOR - # TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available. - # pylint: disable=protected-access - cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle) - _AttachFieldHelpers(cls, extension_handle) - cls.RegisterExtension = staticmethod(RegisterExtension) - - def FromString(s): - message = cls() - message.MergeFromString(s) - return message - cls.FromString = staticmethod(FromString) - - -def _IsPresent(item): - """Given a (FieldDescriptor, value) tuple from _fields, return true if the - value should be included in the list returned by ListFields().""" - - if item[0].label == _FieldDescriptor.LABEL_REPEATED: - return bool(item[1]) - elif item[0].cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - return item[1]._is_present_in_parent - else: - return True - - -def _AddListFieldsMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - - def ListFields(self): - all_fields = [item for item in self._fields.items() if _IsPresent(item)] - all_fields.sort(key = lambda item: item[0].number) - return all_fields - - cls.ListFields = ListFields - -_PROTO3_ERROR_TEMPLATE = \ - ('Protocol message %s has no non-repeated submessage field "%s" ' - 'nor marked as optional') -_PROTO2_ERROR_TEMPLATE = 'Protocol message %s has no non-repeated field "%s"' - -def _AddHasFieldMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - - is_proto3 = (message_descriptor.syntax == "proto3") - error_msg = _PROTO3_ERROR_TEMPLATE if is_proto3 else _PROTO2_ERROR_TEMPLATE - - hassable_fields = {} - for field in message_descriptor.fields: - if field.label == _FieldDescriptor.LABEL_REPEATED: - continue - # For proto3, only submessages and fields inside a oneof have presence. - if (is_proto3 and field.cpp_type != _FieldDescriptor.CPPTYPE_MESSAGE and - not field.containing_oneof): - continue - hassable_fields[field.name] = field - - # Has methods are supported for oneof descriptors. - for oneof in message_descriptor.oneofs: - hassable_fields[oneof.name] = oneof - - def HasField(self, field_name): - try: - field = hassable_fields[field_name] - except KeyError: - raise ValueError(error_msg % (message_descriptor.full_name, field_name)) - - if isinstance(field, descriptor_mod.OneofDescriptor): - try: - return HasField(self, self._oneofs[field].name) - except KeyError: - return False - else: - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - value = self._fields.get(field) - return value is not None and value._is_present_in_parent - else: - return field in self._fields - - cls.HasField = HasField - - -def _AddClearFieldMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - def ClearField(self, field_name): - try: - field = message_descriptor.fields_by_name[field_name] - except KeyError: - try: - field = message_descriptor.oneofs_by_name[field_name] - if field in self._oneofs: - field = self._oneofs[field] - else: - return - except KeyError: - raise ValueError('Protocol message %s has no "%s" field.' % - (message_descriptor.name, field_name)) - - if field in self._fields: - # To match the C++ implementation, we need to invalidate iterators - # for map fields when ClearField() happens. - if hasattr(self._fields[field], 'InvalidateIterators'): - self._fields[field].InvalidateIterators() - - # Note: If the field is a sub-message, its listener will still point - # at us. That's fine, because the worst than can happen is that it - # will call _Modified() and invalidate our byte size. Big deal. - del self._fields[field] - - if self._oneofs.get(field.containing_oneof, None) is field: - del self._oneofs[field.containing_oneof] - - # Always call _Modified() -- even if nothing was changed, this is - # a mutating method, and thus calling it should cause the field to become - # present in the parent message. - self._Modified() - - cls.ClearField = ClearField - - -def _AddClearExtensionMethod(cls): - """Helper for _AddMessageMethods().""" - def ClearExtension(self, extension_handle): - extension_dict._VerifyExtensionHandle(self, extension_handle) - - # Similar to ClearField(), above. - if extension_handle in self._fields: - del self._fields[extension_handle] - self._Modified() - cls.ClearExtension = ClearExtension - - -def _AddHasExtensionMethod(cls): - """Helper for _AddMessageMethods().""" - def HasExtension(self, extension_handle): - extension_dict._VerifyExtensionHandle(self, extension_handle) - if extension_handle.label == _FieldDescriptor.LABEL_REPEATED: - raise KeyError('"%s" is repeated.' % extension_handle.full_name) - - if extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - value = self._fields.get(extension_handle) - return value is not None and value._is_present_in_parent - else: - return extension_handle in self._fields - cls.HasExtension = HasExtension - -def _InternalUnpackAny(msg): - """Unpacks Any message and returns the unpacked message. - - This internal method is different from public Any Unpack method which takes - the target message as argument. _InternalUnpackAny method does not have - target message type and need to find the message type in descriptor pool. - - Args: - msg: An Any message to be unpacked. - - Returns: - The unpacked message. - """ - # TODO(amauryfa): Don't use the factory of generated messages. - # To make Any work with custom factories, use the message factory of the - # parent message. - # pylint: disable=g-import-not-at-top - from google.protobuf import symbol_database - factory = symbol_database.Default() - - type_url = msg.type_url - - if not type_url: - return None - - # TODO(haberman): For now we just strip the hostname. Better logic will be - # required. - type_name = type_url.split('/')[-1] - descriptor = factory.pool.FindMessageTypeByName(type_name) - - if descriptor is None: - return None - - message_class = factory.GetPrototype(descriptor) - message = message_class() - - message.ParseFromString(msg.value) - return message - - -def _AddEqualsMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - def __eq__(self, other): - if (not isinstance(other, message_mod.Message) or - other.DESCRIPTOR != self.DESCRIPTOR): - return False - - if self is other: - return True - - if self.DESCRIPTOR.full_name == _AnyFullTypeName: - any_a = _InternalUnpackAny(self) - any_b = _InternalUnpackAny(other) - if any_a and any_b: - return any_a == any_b - - if not self.ListFields() == other.ListFields(): - return False - - # TODO(jieluo): Fix UnknownFieldSet to consider MessageSet extensions, - # then use it for the comparison. - unknown_fields = list(self._unknown_fields) - unknown_fields.sort() - other_unknown_fields = list(other._unknown_fields) - other_unknown_fields.sort() - return unknown_fields == other_unknown_fields - - cls.__eq__ = __eq__ - - -def _AddStrMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - def __str__(self): - return text_format.MessageToString(self) - cls.__str__ = __str__ - - -def _AddReprMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - def __repr__(self): - return text_format.MessageToString(self) - cls.__repr__ = __repr__ - - -def _AddUnicodeMethod(unused_message_descriptor, cls): - """Helper for _AddMessageMethods().""" - - def __unicode__(self): - return text_format.MessageToString(self, as_utf8=True).decode('utf-8') - cls.__unicode__ = __unicode__ - - -def _BytesForNonRepeatedElement(value, field_number, field_type): - """Returns the number of bytes needed to serialize a non-repeated element. - The returned byte count includes space for tag information and any - other additional space associated with serializing value. - - Args: - value: Value we're serializing. - field_number: Field number of this value. (Since the field number - is stored as part of a varint-encoded tag, this has an impact - on the total bytes required to serialize the value). - field_type: The type of the field. One of the TYPE_* constants - within FieldDescriptor. - """ - try: - fn = type_checkers.TYPE_TO_BYTE_SIZE_FN[field_type] - return fn(field_number, value) - except KeyError: - raise message_mod.EncodeError('Unrecognized field type: %d' % field_type) - - -def _AddByteSizeMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - - def ByteSize(self): - if not self._cached_byte_size_dirty: - return self._cached_byte_size - - size = 0 - descriptor = self.DESCRIPTOR - if descriptor.GetOptions().map_entry: - # Fields of map entry should always be serialized. - size = descriptor.fields_by_name['key']._sizer(self.key) - size += descriptor.fields_by_name['value']._sizer(self.value) - else: - for field_descriptor, field_value in self.ListFields(): - size += field_descriptor._sizer(field_value) - for tag_bytes, value_bytes in self._unknown_fields: - size += len(tag_bytes) + len(value_bytes) - - self._cached_byte_size = size - self._cached_byte_size_dirty = False - self._listener_for_children.dirty = False - return size - - cls.ByteSize = ByteSize - - -def _AddSerializeToStringMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - - def SerializeToString(self, **kwargs): - # Check if the message has all of its required fields set. - if not self.IsInitialized(): - raise message_mod.EncodeError( - 'Message %s is missing required fields: %s' % ( - self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors()))) - return self.SerializePartialToString(**kwargs) - cls.SerializeToString = SerializeToString - - -def _AddSerializePartialToStringMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - - def SerializePartialToString(self, **kwargs): - out = BytesIO() - self._InternalSerialize(out.write, **kwargs) - return out.getvalue() - cls.SerializePartialToString = SerializePartialToString - - def InternalSerialize(self, write_bytes, deterministic=None): - if deterministic is None: - deterministic = ( - api_implementation.IsPythonDefaultSerializationDeterministic()) - else: - deterministic = bool(deterministic) - - descriptor = self.DESCRIPTOR - if descriptor.GetOptions().map_entry: - # Fields of map entry should always be serialized. - descriptor.fields_by_name['key']._encoder( - write_bytes, self.key, deterministic) - descriptor.fields_by_name['value']._encoder( - write_bytes, self.value, deterministic) - else: - for field_descriptor, field_value in self.ListFields(): - field_descriptor._encoder(write_bytes, field_value, deterministic) - for tag_bytes, value_bytes in self._unknown_fields: - write_bytes(tag_bytes) - write_bytes(value_bytes) - cls._InternalSerialize = InternalSerialize - - -def _AddMergeFromStringMethod(message_descriptor, cls): - """Helper for _AddMessageMethods().""" - def MergeFromString(self, serialized): - serialized = memoryview(serialized) - length = len(serialized) - try: - if self._InternalParse(serialized, 0, length) != length: - # The only reason _InternalParse would return early is if it - # encountered an end-group tag. - raise message_mod.DecodeError('Unexpected end-group tag.') - except (IndexError, TypeError): - # Now ord(buf[p:p+1]) == ord('') gets TypeError. - raise message_mod.DecodeError('Truncated message.') - except struct.error as e: - raise message_mod.DecodeError(e) - return length # Return this for legacy reasons. - cls.MergeFromString = MergeFromString - - local_ReadTag = decoder.ReadTag - local_SkipField = decoder.SkipField - decoders_by_tag = cls._decoders_by_tag - - def InternalParse(self, buffer, pos, end): - """Create a message from serialized bytes. - - Args: - self: Message, instance of the proto message object. - buffer: memoryview of the serialized data. - pos: int, position to start in the serialized data. - end: int, end position of the serialized data. - - Returns: - Message object. - """ - # Guard against internal misuse, since this function is called internally - # quite extensively, and its easy to accidentally pass bytes. - assert isinstance(buffer, memoryview) - self._Modified() - field_dict = self._fields - # pylint: disable=protected-access - unknown_field_set = self._unknown_field_set - while pos != end: - (tag_bytes, new_pos) = local_ReadTag(buffer, pos) - field_decoder, field_desc = decoders_by_tag.get(tag_bytes, (None, None)) - if field_decoder is None: - if not self._unknown_fields: # pylint: disable=protected-access - self._unknown_fields = [] # pylint: disable=protected-access - if unknown_field_set is None: - # pylint: disable=protected-access - self._unknown_field_set = containers.UnknownFieldSet() - # pylint: disable=protected-access - unknown_field_set = self._unknown_field_set - # pylint: disable=protected-access - (tag, _) = decoder._DecodeVarint(tag_bytes, 0) - field_number, wire_type = wire_format.UnpackTag(tag) - if field_number == 0: - raise message_mod.DecodeError('Field number 0 is illegal.') - # TODO(jieluo): remove old_pos. - old_pos = new_pos - (data, new_pos) = decoder._DecodeUnknownField( - buffer, new_pos, wire_type) # pylint: disable=protected-access - if new_pos == -1: - return pos - # pylint: disable=protected-access - unknown_field_set._add(field_number, wire_type, data) - # TODO(jieluo): remove _unknown_fields. - new_pos = local_SkipField(buffer, old_pos, end, tag_bytes) - if new_pos == -1: - return pos - self._unknown_fields.append( - (tag_bytes, buffer[old_pos:new_pos].tobytes())) - pos = new_pos - else: - pos = field_decoder(buffer, new_pos, end, self, field_dict) - if field_desc: - self._UpdateOneofState(field_desc) - return pos - cls._InternalParse = InternalParse - - -def _AddIsInitializedMethod(message_descriptor, cls): - """Adds the IsInitialized and FindInitializationError methods to the - protocol message class.""" - - required_fields = [field for field in message_descriptor.fields - if field.label == _FieldDescriptor.LABEL_REQUIRED] - - def IsInitialized(self, errors=None): - """Checks if all required fields of a message are set. - - Args: - errors: A list which, if provided, will be populated with the field - paths of all missing required fields. - - Returns: - True iff the specified message has all required fields set. - """ - - # Performance is critical so we avoid HasField() and ListFields(). - - for field in required_fields: - if (field not in self._fields or - (field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and - not self._fields[field]._is_present_in_parent)): - if errors is not None: - errors.extend(self.FindInitializationErrors()) - return False - - for field, value in list(self._fields.items()): # dict can change size! - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - if field.label == _FieldDescriptor.LABEL_REPEATED: - if (field.message_type.has_options and - field.message_type.GetOptions().map_entry): - continue - for element in value: - if not element.IsInitialized(): - if errors is not None: - errors.extend(self.FindInitializationErrors()) - return False - elif value._is_present_in_parent and not value.IsInitialized(): - if errors is not None: - errors.extend(self.FindInitializationErrors()) - return False - - return True - - cls.IsInitialized = IsInitialized - - def FindInitializationErrors(self): - """Finds required fields which are not initialized. - - Returns: - A list of strings. Each string is a path to an uninitialized field from - the top-level message, e.g. "foo.bar[5].baz". - """ - - errors = [] # simplify things - - for field in required_fields: - if not self.HasField(field.name): - errors.append(field.name) - - for field, value in self.ListFields(): - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - if field.is_extension: - name = '(%s)' % field.full_name - else: - name = field.name - - if _IsMapField(field): - if _IsMessageMapField(field): - for key in value: - element = value[key] - prefix = '%s[%s].' % (name, key) - sub_errors = element.FindInitializationErrors() - errors += [prefix + error for error in sub_errors] - else: - # ScalarMaps can't have any initialization errors. - pass - elif field.label == _FieldDescriptor.LABEL_REPEATED: - for i in range(len(value)): - element = value[i] - prefix = '%s[%d].' % (name, i) - sub_errors = element.FindInitializationErrors() - errors += [prefix + error for error in sub_errors] - else: - prefix = name + '.' - sub_errors = value.FindInitializationErrors() - errors += [prefix + error for error in sub_errors] - - return errors - - cls.FindInitializationErrors = FindInitializationErrors - - -def _FullyQualifiedClassName(klass): - module = klass.__module__ - name = getattr(klass, '__qualname__', klass.__name__) - if module in (None, 'builtins', '__builtin__'): - return name - return module + '.' + name - - -def _AddMergeFromMethod(cls): - LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED - CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE - - def MergeFrom(self, msg): - if not isinstance(msg, cls): - raise TypeError( - 'Parameter to MergeFrom() must be instance of same class: ' - 'expected %s got %s.' % (_FullyQualifiedClassName(cls), - _FullyQualifiedClassName(msg.__class__))) - - assert msg is not self - self._Modified() - - fields = self._fields - - for field, value in msg._fields.items(): - if field.label == LABEL_REPEATED: - field_value = fields.get(field) - if field_value is None: - # Construct a new object to represent this field. - field_value = field._default_constructor(self) - fields[field] = field_value - field_value.MergeFrom(value) - elif field.cpp_type == CPPTYPE_MESSAGE: - if value._is_present_in_parent: - field_value = fields.get(field) - if field_value is None: - # Construct a new object to represent this field. - field_value = field._default_constructor(self) - fields[field] = field_value - field_value.MergeFrom(value) - else: - self._fields[field] = value - if field.containing_oneof: - self._UpdateOneofState(field) - - if msg._unknown_fields: - if not self._unknown_fields: - self._unknown_fields = [] - self._unknown_fields.extend(msg._unknown_fields) - # pylint: disable=protected-access - if self._unknown_field_set is None: - self._unknown_field_set = containers.UnknownFieldSet() - self._unknown_field_set._extend(msg._unknown_field_set) - - cls.MergeFrom = MergeFrom - - -def _AddWhichOneofMethod(message_descriptor, cls): - def WhichOneof(self, oneof_name): - """Returns the name of the currently set field inside a oneof, or None.""" - try: - field = message_descriptor.oneofs_by_name[oneof_name] - except KeyError: - raise ValueError( - 'Protocol message has no oneof "%s" field.' % oneof_name) - - nested_field = self._oneofs.get(field, None) - if nested_field is not None and self.HasField(nested_field.name): - return nested_field.name - else: - return None - - cls.WhichOneof = WhichOneof - - -def _Clear(self): - # Clear fields. - self._fields = {} - self._unknown_fields = () - # pylint: disable=protected-access - if self._unknown_field_set is not None: - self._unknown_field_set._clear() - self._unknown_field_set = None - - self._oneofs = {} - self._Modified() - - -def _UnknownFields(self): - if self._unknown_field_set is None: # pylint: disable=protected-access - # pylint: disable=protected-access - self._unknown_field_set = containers.UnknownFieldSet() - return self._unknown_field_set # pylint: disable=protected-access - - -def _DiscardUnknownFields(self): - self._unknown_fields = [] - self._unknown_field_set = None # pylint: disable=protected-access - for field, value in self.ListFields(): - if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: - if _IsMapField(field): - if _IsMessageMapField(field): - for key in value: - value[key].DiscardUnknownFields() - elif field.label == _FieldDescriptor.LABEL_REPEATED: - for sub_message in value: - sub_message.DiscardUnknownFields() - else: - value.DiscardUnknownFields() - - -def _SetListener(self, listener): - if listener is None: - self._listener = message_listener_mod.NullMessageListener() - else: - self._listener = listener - - -def _AddMessageMethods(message_descriptor, cls): - """Adds implementations of all Message methods to cls.""" - _AddListFieldsMethod(message_descriptor, cls) - _AddHasFieldMethod(message_descriptor, cls) - _AddClearFieldMethod(message_descriptor, cls) - if message_descriptor.is_extendable: - _AddClearExtensionMethod(cls) - _AddHasExtensionMethod(cls) - _AddEqualsMethod(message_descriptor, cls) - _AddStrMethod(message_descriptor, cls) - _AddReprMethod(message_descriptor, cls) - _AddUnicodeMethod(message_descriptor, cls) - _AddByteSizeMethod(message_descriptor, cls) - _AddSerializeToStringMethod(message_descriptor, cls) - _AddSerializePartialToStringMethod(message_descriptor, cls) - _AddMergeFromStringMethod(message_descriptor, cls) - _AddIsInitializedMethod(message_descriptor, cls) - _AddMergeFromMethod(cls) - _AddWhichOneofMethod(message_descriptor, cls) - # Adds methods which do not depend on cls. - cls.Clear = _Clear - cls.UnknownFields = _UnknownFields - cls.DiscardUnknownFields = _DiscardUnknownFields - cls._SetListener = _SetListener - - -def _AddPrivateHelperMethods(message_descriptor, cls): - """Adds implementation of private helper methods to cls.""" - - def Modified(self): - """Sets the _cached_byte_size_dirty bit to true, - and propagates this to our listener iff this was a state change. - """ - - # Note: Some callers check _cached_byte_size_dirty before calling - # _Modified() as an extra optimization. So, if this method is ever - # changed such that it does stuff even when _cached_byte_size_dirty is - # already true, the callers need to be updated. - if not self._cached_byte_size_dirty: - self._cached_byte_size_dirty = True - self._listener_for_children.dirty = True - self._is_present_in_parent = True - self._listener.Modified() - - def _UpdateOneofState(self, field): - """Sets field as the active field in its containing oneof. - - Will also delete currently active field in the oneof, if it is different - from the argument. Does not mark the message as modified. - """ - other_field = self._oneofs.setdefault(field.containing_oneof, field) - if other_field is not field: - del self._fields[other_field] - self._oneofs[field.containing_oneof] = field - - cls._Modified = Modified - cls.SetInParent = Modified - cls._UpdateOneofState = _UpdateOneofState - - -class _Listener(object): - - """MessageListener implementation that a parent message registers with its - child message. - - In order to support semantics like: - - foo.bar.baz.qux = 23 - assert foo.HasField('bar') - - ...child objects must have back references to their parents. - This helper class is at the heart of this support. - """ - - def __init__(self, parent_message): - """Args: - parent_message: The message whose _Modified() method we should call when - we receive Modified() messages. - """ - # This listener establishes a back reference from a child (contained) object - # to its parent (containing) object. We make this a weak reference to avoid - # creating cyclic garbage when the client finishes with the 'parent' object - # in the tree. - if isinstance(parent_message, weakref.ProxyType): - self._parent_message_weakref = parent_message - else: - self._parent_message_weakref = weakref.proxy(parent_message) - - # As an optimization, we also indicate directly on the listener whether - # or not the parent message is dirty. This way we can avoid traversing - # up the tree in the common case. - self.dirty = False - - def Modified(self): - if self.dirty: - return - try: - # Propagate the signal to our parents iff this is the first field set. - self._parent_message_weakref._Modified() - except ReferenceError: - # We can get here if a client has kept a reference to a child object, - # and is now setting a field on it, but the child's parent has been - # garbage-collected. This is not an error. - pass - - -class _OneofListener(_Listener): - """Special listener implementation for setting composite oneof fields.""" - - def __init__(self, parent_message, field): - """Args: - parent_message: The message whose _Modified() method we should call when - we receive Modified() messages. - field: The descriptor of the field being set in the parent message. - """ - super(_OneofListener, self).__init__(parent_message) - self._field = field - - def Modified(self): - """Also updates the state of the containing oneof in the parent message.""" - try: - self._parent_message_weakref._UpdateOneofState(self._field) - super(_OneofListener, self).Modified() - except ReferenceError: - pass diff --git a/scripts/protobuf3/protobuf3/internal/type_checkers.py b/scripts/protobuf3/protobuf3/internal/type_checkers.py deleted file mode 100644 index a53e71f..0000000 --- a/scripts/protobuf3/protobuf3/internal/type_checkers.py +++ /dev/null @@ -1,435 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Provides type checking routines. - -This module defines type checking utilities in the forms of dictionaries: - -VALUE_CHECKERS: A dictionary of field types and a value validation object. -TYPE_TO_BYTE_SIZE_FN: A dictionary with field types and a size computing - function. -TYPE_TO_SERIALIZE_METHOD: A dictionary with field types and serialization - function. -FIELD_TYPE_TO_WIRE_TYPE: A dictionary with field typed and their - corresponding wire types. -TYPE_TO_DESERIALIZE_METHOD: A dictionary with field types and deserialization - function. -""" - -__author__ = 'robinson@google.com (Will Robinson)' - -import ctypes -import numbers - -from google.protobuf.internal import decoder -from google.protobuf.internal import encoder -from google.protobuf.internal import wire_format -from google.protobuf import descriptor - -_FieldDescriptor = descriptor.FieldDescriptor - - -def TruncateToFourByteFloat(original): - return ctypes.c_float(original).value - - -def ToShortestFloat(original): - """Returns the shortest float that has same value in wire.""" - # All 4 byte floats have between 6 and 9 significant digits, so we - # start with 6 as the lower bound. - # It has to be iterative because use '.9g' directly can not get rid - # of the noises for most values. For example if set a float_field=0.9 - # use '.9g' will print 0.899999976. - precision = 6 - rounded = float('{0:.{1}g}'.format(original, precision)) - while TruncateToFourByteFloat(rounded) != original: - precision += 1 - rounded = float('{0:.{1}g}'.format(original, precision)) - return rounded - - -def SupportsOpenEnums(field_descriptor): - return field_descriptor.containing_type.syntax == 'proto3' - - -def GetTypeChecker(field): - """Returns a type checker for a message field of the specified types. - - Args: - field: FieldDescriptor object for this field. - - Returns: - An instance of TypeChecker which can be used to verify the types - of values assigned to a field of the specified type. - """ - if (field.cpp_type == _FieldDescriptor.CPPTYPE_STRING and - field.type == _FieldDescriptor.TYPE_STRING): - return UnicodeValueChecker() - if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM: - if SupportsOpenEnums(field): - # When open enums are supported, any int32 can be assigned. - return _VALUE_CHECKERS[_FieldDescriptor.CPPTYPE_INT32] - else: - return EnumValueChecker(field.enum_type) - return _VALUE_CHECKERS[field.cpp_type] - - -# None of the typecheckers below make any attempt to guard against people -# subclassing builtin types and doing weird things. We're not trying to -# protect against malicious clients here, just people accidentally shooting -# themselves in the foot in obvious ways. -class TypeChecker(object): - - """Type checker used to catch type errors as early as possible - when the client is setting scalar fields in protocol messages. - """ - - def __init__(self, *acceptable_types): - self._acceptable_types = acceptable_types - - def CheckValue(self, proposed_value): - """Type check the provided value and return it. - - The returned value might have been normalized to another type. - """ - if not isinstance(proposed_value, self._acceptable_types): - message = ('%.1024r has type %s, but expected one of: %s' % - (proposed_value, type(proposed_value), self._acceptable_types)) - raise TypeError(message) - return proposed_value - - -class TypeCheckerWithDefault(TypeChecker): - - def __init__(self, default_value, *acceptable_types): - TypeChecker.__init__(self, *acceptable_types) - self._default_value = default_value - - def DefaultValue(self): - return self._default_value - - -class BoolValueChecker(object): - """Type checker used for bool fields.""" - - def CheckValue(self, proposed_value): - if not hasattr(proposed_value, '__index__') or ( - type(proposed_value).__module__ == 'numpy' and - type(proposed_value).__name__ == 'ndarray'): - message = ('%.1024r has type %s, but expected one of: %s' % - (proposed_value, type(proposed_value), (bool, int))) - raise TypeError(message) - return bool(proposed_value) - - def DefaultValue(self): - return False - - -# IntValueChecker and its subclasses perform integer type-checks -# and bounds-checks. -class IntValueChecker(object): - - """Checker used for integer fields. Performs type-check and range check.""" - - def CheckValue(self, proposed_value): - if not hasattr(proposed_value, '__index__') or ( - type(proposed_value).__module__ == 'numpy' and - type(proposed_value).__name__ == 'ndarray'): - message = ('%.1024r has type %s, but expected one of: %s' % - (proposed_value, type(proposed_value), (int,))) - raise TypeError(message) - - if not self._MIN <= int(proposed_value) <= self._MAX: - raise ValueError('Value out of range: %d' % proposed_value) - # We force all values to int to make alternate implementations where the - # distinction is more significant (e.g. the C++ implementation) simpler. - proposed_value = int(proposed_value) - return proposed_value - - def DefaultValue(self): - return 0 - - -class EnumValueChecker(object): - - """Checker used for enum fields. Performs type-check and range check.""" - - def __init__(self, enum_type): - self._enum_type = enum_type - - def CheckValue(self, proposed_value): - if not isinstance(proposed_value, numbers.Integral): - message = ('%.1024r has type %s, but expected one of: %s' % - (proposed_value, type(proposed_value), (int,))) - raise TypeError(message) - if int(proposed_value) not in self._enum_type.values_by_number: - raise ValueError('Unknown enum value: %d' % proposed_value) - return proposed_value - - def DefaultValue(self): - return self._enum_type.values[0].number - - -class UnicodeValueChecker(object): - - """Checker used for string fields. - - Always returns a unicode value, even if the input is of type str. - """ - - def CheckValue(self, proposed_value): - if not isinstance(proposed_value, (bytes, str)): - message = ('%.1024r has type %s, but expected one of: %s' % - (proposed_value, type(proposed_value), (bytes, str))) - raise TypeError(message) - - # If the value is of type 'bytes' make sure that it is valid UTF-8 data. - if isinstance(proposed_value, bytes): - try: - proposed_value = proposed_value.decode('utf-8') - except UnicodeDecodeError: - raise ValueError('%.1024r has type bytes, but isn\'t valid UTF-8 ' - 'encoding. Non-UTF-8 strings must be converted to ' - 'unicode objects before being added.' % - (proposed_value)) - else: - try: - proposed_value.encode('utf8') - except UnicodeEncodeError: - raise ValueError('%.1024r isn\'t a valid unicode string and ' - 'can\'t be encoded in UTF-8.'% - (proposed_value)) - - return proposed_value - - def DefaultValue(self): - return u"" - - -class Int32ValueChecker(IntValueChecker): - # We're sure to use ints instead of longs here since comparison may be more - # efficient. - _MIN = -2147483648 - _MAX = 2147483647 - - -class Uint32ValueChecker(IntValueChecker): - _MIN = 0 - _MAX = (1 << 32) - 1 - - -class Int64ValueChecker(IntValueChecker): - _MIN = -(1 << 63) - _MAX = (1 << 63) - 1 - - -class Uint64ValueChecker(IntValueChecker): - _MIN = 0 - _MAX = (1 << 64) - 1 - - -# The max 4 bytes float is about 3.4028234663852886e+38 -_FLOAT_MAX = float.fromhex('0x1.fffffep+127') -_FLOAT_MIN = -_FLOAT_MAX -_INF = float('inf') -_NEG_INF = float('-inf') - - -class DoubleValueChecker(object): - """Checker used for double fields. - - Performs type-check and range check. - """ - - def CheckValue(self, proposed_value): - """Check and convert proposed_value to float.""" - if (not hasattr(proposed_value, '__float__') and - not hasattr(proposed_value, '__index__')) or ( - type(proposed_value).__module__ == 'numpy' and - type(proposed_value).__name__ == 'ndarray'): - message = ('%.1024r has type %s, but expected one of: int, float' % - (proposed_value, type(proposed_value))) - raise TypeError(message) - return float(proposed_value) - - def DefaultValue(self): - return 0.0 - - -class FloatValueChecker(DoubleValueChecker): - """Checker used for float fields. - - Performs type-check and range check. - - Values exceeding a 32-bit float will be converted to inf/-inf. - """ - - def CheckValue(self, proposed_value): - """Check and convert proposed_value to float.""" - converted_value = super().CheckValue(proposed_value) - # This inf rounding matches the C++ proto SafeDoubleToFloat logic. - if converted_value > _FLOAT_MAX: - return _INF - if converted_value < _FLOAT_MIN: - return _NEG_INF - - return TruncateToFourByteFloat(converted_value) - -# Type-checkers for all scalar CPPTYPEs. -_VALUE_CHECKERS = { - _FieldDescriptor.CPPTYPE_INT32: Int32ValueChecker(), - _FieldDescriptor.CPPTYPE_INT64: Int64ValueChecker(), - _FieldDescriptor.CPPTYPE_UINT32: Uint32ValueChecker(), - _FieldDescriptor.CPPTYPE_UINT64: Uint64ValueChecker(), - _FieldDescriptor.CPPTYPE_DOUBLE: DoubleValueChecker(), - _FieldDescriptor.CPPTYPE_FLOAT: FloatValueChecker(), - _FieldDescriptor.CPPTYPE_BOOL: BoolValueChecker(), - _FieldDescriptor.CPPTYPE_STRING: TypeCheckerWithDefault(b'', bytes), -} - - -# Map from field type to a function F, such that F(field_num, value) -# gives the total byte size for a value of the given type. This -# byte size includes tag information and any other additional space -# associated with serializing "value". -TYPE_TO_BYTE_SIZE_FN = { - _FieldDescriptor.TYPE_DOUBLE: wire_format.DoubleByteSize, - _FieldDescriptor.TYPE_FLOAT: wire_format.FloatByteSize, - _FieldDescriptor.TYPE_INT64: wire_format.Int64ByteSize, - _FieldDescriptor.TYPE_UINT64: wire_format.UInt64ByteSize, - _FieldDescriptor.TYPE_INT32: wire_format.Int32ByteSize, - _FieldDescriptor.TYPE_FIXED64: wire_format.Fixed64ByteSize, - _FieldDescriptor.TYPE_FIXED32: wire_format.Fixed32ByteSize, - _FieldDescriptor.TYPE_BOOL: wire_format.BoolByteSize, - _FieldDescriptor.TYPE_STRING: wire_format.StringByteSize, - _FieldDescriptor.TYPE_GROUP: wire_format.GroupByteSize, - _FieldDescriptor.TYPE_MESSAGE: wire_format.MessageByteSize, - _FieldDescriptor.TYPE_BYTES: wire_format.BytesByteSize, - _FieldDescriptor.TYPE_UINT32: wire_format.UInt32ByteSize, - _FieldDescriptor.TYPE_ENUM: wire_format.EnumByteSize, - _FieldDescriptor.TYPE_SFIXED32: wire_format.SFixed32ByteSize, - _FieldDescriptor.TYPE_SFIXED64: wire_format.SFixed64ByteSize, - _FieldDescriptor.TYPE_SINT32: wire_format.SInt32ByteSize, - _FieldDescriptor.TYPE_SINT64: wire_format.SInt64ByteSize - } - - -# Maps from field types to encoder constructors. -TYPE_TO_ENCODER = { - _FieldDescriptor.TYPE_DOUBLE: encoder.DoubleEncoder, - _FieldDescriptor.TYPE_FLOAT: encoder.FloatEncoder, - _FieldDescriptor.TYPE_INT64: encoder.Int64Encoder, - _FieldDescriptor.TYPE_UINT64: encoder.UInt64Encoder, - _FieldDescriptor.TYPE_INT32: encoder.Int32Encoder, - _FieldDescriptor.TYPE_FIXED64: encoder.Fixed64Encoder, - _FieldDescriptor.TYPE_FIXED32: encoder.Fixed32Encoder, - _FieldDescriptor.TYPE_BOOL: encoder.BoolEncoder, - _FieldDescriptor.TYPE_STRING: encoder.StringEncoder, - _FieldDescriptor.TYPE_GROUP: encoder.GroupEncoder, - _FieldDescriptor.TYPE_MESSAGE: encoder.MessageEncoder, - _FieldDescriptor.TYPE_BYTES: encoder.BytesEncoder, - _FieldDescriptor.TYPE_UINT32: encoder.UInt32Encoder, - _FieldDescriptor.TYPE_ENUM: encoder.EnumEncoder, - _FieldDescriptor.TYPE_SFIXED32: encoder.SFixed32Encoder, - _FieldDescriptor.TYPE_SFIXED64: encoder.SFixed64Encoder, - _FieldDescriptor.TYPE_SINT32: encoder.SInt32Encoder, - _FieldDescriptor.TYPE_SINT64: encoder.SInt64Encoder, - } - - -# Maps from field types to sizer constructors. -TYPE_TO_SIZER = { - _FieldDescriptor.TYPE_DOUBLE: encoder.DoubleSizer, - _FieldDescriptor.TYPE_FLOAT: encoder.FloatSizer, - _FieldDescriptor.TYPE_INT64: encoder.Int64Sizer, - _FieldDescriptor.TYPE_UINT64: encoder.UInt64Sizer, - _FieldDescriptor.TYPE_INT32: encoder.Int32Sizer, - _FieldDescriptor.TYPE_FIXED64: encoder.Fixed64Sizer, - _FieldDescriptor.TYPE_FIXED32: encoder.Fixed32Sizer, - _FieldDescriptor.TYPE_BOOL: encoder.BoolSizer, - _FieldDescriptor.TYPE_STRING: encoder.StringSizer, - _FieldDescriptor.TYPE_GROUP: encoder.GroupSizer, - _FieldDescriptor.TYPE_MESSAGE: encoder.MessageSizer, - _FieldDescriptor.TYPE_BYTES: encoder.BytesSizer, - _FieldDescriptor.TYPE_UINT32: encoder.UInt32Sizer, - _FieldDescriptor.TYPE_ENUM: encoder.EnumSizer, - _FieldDescriptor.TYPE_SFIXED32: encoder.SFixed32Sizer, - _FieldDescriptor.TYPE_SFIXED64: encoder.SFixed64Sizer, - _FieldDescriptor.TYPE_SINT32: encoder.SInt32Sizer, - _FieldDescriptor.TYPE_SINT64: encoder.SInt64Sizer, - } - - -# Maps from field type to a decoder constructor. -TYPE_TO_DECODER = { - _FieldDescriptor.TYPE_DOUBLE: decoder.DoubleDecoder, - _FieldDescriptor.TYPE_FLOAT: decoder.FloatDecoder, - _FieldDescriptor.TYPE_INT64: decoder.Int64Decoder, - _FieldDescriptor.TYPE_UINT64: decoder.UInt64Decoder, - _FieldDescriptor.TYPE_INT32: decoder.Int32Decoder, - _FieldDescriptor.TYPE_FIXED64: decoder.Fixed64Decoder, - _FieldDescriptor.TYPE_FIXED32: decoder.Fixed32Decoder, - _FieldDescriptor.TYPE_BOOL: decoder.BoolDecoder, - _FieldDescriptor.TYPE_STRING: decoder.StringDecoder, - _FieldDescriptor.TYPE_GROUP: decoder.GroupDecoder, - _FieldDescriptor.TYPE_MESSAGE: decoder.MessageDecoder, - _FieldDescriptor.TYPE_BYTES: decoder.BytesDecoder, - _FieldDescriptor.TYPE_UINT32: decoder.UInt32Decoder, - _FieldDescriptor.TYPE_ENUM: decoder.EnumDecoder, - _FieldDescriptor.TYPE_SFIXED32: decoder.SFixed32Decoder, - _FieldDescriptor.TYPE_SFIXED64: decoder.SFixed64Decoder, - _FieldDescriptor.TYPE_SINT32: decoder.SInt32Decoder, - _FieldDescriptor.TYPE_SINT64: decoder.SInt64Decoder, - } - -# Maps from field type to expected wiretype. -FIELD_TYPE_TO_WIRE_TYPE = { - _FieldDescriptor.TYPE_DOUBLE: wire_format.WIRETYPE_FIXED64, - _FieldDescriptor.TYPE_FLOAT: wire_format.WIRETYPE_FIXED32, - _FieldDescriptor.TYPE_INT64: wire_format.WIRETYPE_VARINT, - _FieldDescriptor.TYPE_UINT64: wire_format.WIRETYPE_VARINT, - _FieldDescriptor.TYPE_INT32: wire_format.WIRETYPE_VARINT, - _FieldDescriptor.TYPE_FIXED64: wire_format.WIRETYPE_FIXED64, - _FieldDescriptor.TYPE_FIXED32: wire_format.WIRETYPE_FIXED32, - _FieldDescriptor.TYPE_BOOL: wire_format.WIRETYPE_VARINT, - _FieldDescriptor.TYPE_STRING: - wire_format.WIRETYPE_LENGTH_DELIMITED, - _FieldDescriptor.TYPE_GROUP: wire_format.WIRETYPE_START_GROUP, - _FieldDescriptor.TYPE_MESSAGE: - wire_format.WIRETYPE_LENGTH_DELIMITED, - _FieldDescriptor.TYPE_BYTES: - wire_format.WIRETYPE_LENGTH_DELIMITED, - _FieldDescriptor.TYPE_UINT32: wire_format.WIRETYPE_VARINT, - _FieldDescriptor.TYPE_ENUM: wire_format.WIRETYPE_VARINT, - _FieldDescriptor.TYPE_SFIXED32: wire_format.WIRETYPE_FIXED32, - _FieldDescriptor.TYPE_SFIXED64: wire_format.WIRETYPE_FIXED64, - _FieldDescriptor.TYPE_SINT32: wire_format.WIRETYPE_VARINT, - _FieldDescriptor.TYPE_SINT64: wire_format.WIRETYPE_VARINT, - } diff --git a/scripts/protobuf3/protobuf3/internal/well_known_types.py b/scripts/protobuf3/protobuf3/internal/well_known_types.py deleted file mode 100644 index b581ab7..0000000 --- a/scripts/protobuf3/protobuf3/internal/well_known_types.py +++ /dev/null @@ -1,878 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Contains well known classes. - -This files defines well known classes which need extra maintenance including: - - Any - - Duration - - FieldMask - - Struct - - Timestamp -""" - -__author__ = 'jieluo@google.com (Jie Luo)' - -import calendar -import collections.abc -import datetime - -from google.protobuf.descriptor import FieldDescriptor - -_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S' -_NANOS_PER_SECOND = 1000000000 -_NANOS_PER_MILLISECOND = 1000000 -_NANOS_PER_MICROSECOND = 1000 -_MILLIS_PER_SECOND = 1000 -_MICROS_PER_SECOND = 1000000 -_SECONDS_PER_DAY = 24 * 3600 -_DURATION_SECONDS_MAX = 315576000000 - - -class Any(object): - """Class for Any Message type.""" - - __slots__ = () - - def Pack(self, msg, type_url_prefix='type.googleapis.com/', - deterministic=None): - """Packs the specified message into current Any message.""" - if len(type_url_prefix) < 1 or type_url_prefix[-1] != '/': - self.type_url = '%s/%s' % (type_url_prefix, msg.DESCRIPTOR.full_name) - else: - self.type_url = '%s%s' % (type_url_prefix, msg.DESCRIPTOR.full_name) - self.value = msg.SerializeToString(deterministic=deterministic) - - def Unpack(self, msg): - """Unpacks the current Any message into specified message.""" - descriptor = msg.DESCRIPTOR - if not self.Is(descriptor): - return False - msg.ParseFromString(self.value) - return True - - def TypeName(self): - """Returns the protobuf type name of the inner message.""" - # Only last part is to be used: b/25630112 - return self.type_url.split('/')[-1] - - def Is(self, descriptor): - """Checks if this Any represents the given protobuf type.""" - return '/' in self.type_url and self.TypeName() == descriptor.full_name - - -_EPOCH_DATETIME_NAIVE = datetime.datetime.utcfromtimestamp(0) -_EPOCH_DATETIME_AWARE = datetime.datetime.fromtimestamp( - 0, tz=datetime.timezone.utc) - - -class Timestamp(object): - """Class for Timestamp message type.""" - - __slots__ = () - - def ToJsonString(self): - """Converts Timestamp to RFC 3339 date string format. - - Returns: - A string converted from timestamp. The string is always Z-normalized - and uses 3, 6 or 9 fractional digits as required to represent the - exact time. Example of the return format: '1972-01-01T10:00:20.021Z' - """ - nanos = self.nanos % _NANOS_PER_SECOND - total_sec = self.seconds + (self.nanos - nanos) // _NANOS_PER_SECOND - seconds = total_sec % _SECONDS_PER_DAY - days = (total_sec - seconds) // _SECONDS_PER_DAY - dt = datetime.datetime(1970, 1, 1) + datetime.timedelta(days, seconds) - - result = dt.isoformat() - if (nanos % 1e9) == 0: - # If there are 0 fractional digits, the fractional - # point '.' should be omitted when serializing. - return result + 'Z' - if (nanos % 1e6) == 0: - # Serialize 3 fractional digits. - return result + '.%03dZ' % (nanos / 1e6) - if (nanos % 1e3) == 0: - # Serialize 6 fractional digits. - return result + '.%06dZ' % (nanos / 1e3) - # Serialize 9 fractional digits. - return result + '.%09dZ' % nanos - - def FromJsonString(self, value): - """Parse a RFC 3339 date string format to Timestamp. - - Args: - value: A date string. Any fractional digits (or none) and any offset are - accepted as long as they fit into nano-seconds precision. - Example of accepted format: '1972-01-01T10:00:20.021-05:00' - - Raises: - ValueError: On parsing problems. - """ - if not isinstance(value, str): - raise ValueError('Timestamp JSON value not a string: {!r}'.format(value)) - timezone_offset = value.find('Z') - if timezone_offset == -1: - timezone_offset = value.find('+') - if timezone_offset == -1: - timezone_offset = value.rfind('-') - if timezone_offset == -1: - raise ValueError( - 'Failed to parse timestamp: missing valid timezone offset.') - time_value = value[0:timezone_offset] - # Parse datetime and nanos. - point_position = time_value.find('.') - if point_position == -1: - second_value = time_value - nano_value = '' - else: - second_value = time_value[:point_position] - nano_value = time_value[point_position + 1:] - if 't' in second_value: - raise ValueError( - 'time data \'{0}\' does not match format \'%Y-%m-%dT%H:%M:%S\', ' - 'lowercase \'t\' is not accepted'.format(second_value)) - date_object = datetime.datetime.strptime(second_value, _TIMESTAMPFOMAT) - td = date_object - datetime.datetime(1970, 1, 1) - seconds = td.seconds + td.days * _SECONDS_PER_DAY - if len(nano_value) > 9: - raise ValueError( - 'Failed to parse Timestamp: nanos {0} more than ' - '9 fractional digits.'.format(nano_value)) - if nano_value: - nanos = round(float('0.' + nano_value) * 1e9) - else: - nanos = 0 - # Parse timezone offsets. - if value[timezone_offset] == 'Z': - if len(value) != timezone_offset + 1: - raise ValueError('Failed to parse timestamp: invalid trailing' - ' data {0}.'.format(value)) - else: - timezone = value[timezone_offset:] - pos = timezone.find(':') - if pos == -1: - raise ValueError( - 'Invalid timezone offset value: {0}.'.format(timezone)) - if timezone[0] == '+': - seconds -= (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60 - else: - seconds += (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60 - # Set seconds and nanos - self.seconds = int(seconds) - self.nanos = int(nanos) - - def GetCurrentTime(self): - """Get the current UTC into Timestamp.""" - self.FromDatetime(datetime.datetime.utcnow()) - - def ToNanoseconds(self): - """Converts Timestamp to nanoseconds since epoch.""" - return self.seconds * _NANOS_PER_SECOND + self.nanos - - def ToMicroseconds(self): - """Converts Timestamp to microseconds since epoch.""" - return (self.seconds * _MICROS_PER_SECOND + - self.nanos // _NANOS_PER_MICROSECOND) - - def ToMilliseconds(self): - """Converts Timestamp to milliseconds since epoch.""" - return (self.seconds * _MILLIS_PER_SECOND + - self.nanos // _NANOS_PER_MILLISECOND) - - def ToSeconds(self): - """Converts Timestamp to seconds since epoch.""" - return self.seconds - - def FromNanoseconds(self, nanos): - """Converts nanoseconds since epoch to Timestamp.""" - self.seconds = nanos // _NANOS_PER_SECOND - self.nanos = nanos % _NANOS_PER_SECOND - - def FromMicroseconds(self, micros): - """Converts microseconds since epoch to Timestamp.""" - self.seconds = micros // _MICROS_PER_SECOND - self.nanos = (micros % _MICROS_PER_SECOND) * _NANOS_PER_MICROSECOND - - def FromMilliseconds(self, millis): - """Converts milliseconds since epoch to Timestamp.""" - self.seconds = millis // _MILLIS_PER_SECOND - self.nanos = (millis % _MILLIS_PER_SECOND) * _NANOS_PER_MILLISECOND - - def FromSeconds(self, seconds): - """Converts seconds since epoch to Timestamp.""" - self.seconds = seconds - self.nanos = 0 - - def ToDatetime(self, tzinfo=None): - """Converts Timestamp to a datetime. - - Args: - tzinfo: A datetime.tzinfo subclass; defaults to None. - - Returns: - If tzinfo is None, returns a timezone-naive UTC datetime (with no timezone - information, i.e. not aware that it's UTC). - - Otherwise, returns a timezone-aware datetime in the input timezone. - """ - delta = datetime.timedelta( - seconds=self.seconds, - microseconds=_RoundTowardZero(self.nanos, _NANOS_PER_MICROSECOND)) - if tzinfo is None: - return _EPOCH_DATETIME_NAIVE + delta - else: - return _EPOCH_DATETIME_AWARE.astimezone(tzinfo) + delta - - def FromDatetime(self, dt): - """Converts datetime to Timestamp. - - Args: - dt: A datetime. If it's timezone-naive, it's assumed to be in UTC. - """ - # Using this guide: http://wiki.python.org/moin/WorkingWithTime - # And this conversion guide: http://docs.python.org/library/time.html - - # Turn the date parameter into a tuple (struct_time) that can then be - # manipulated into a long value of seconds. During the conversion from - # struct_time to long, the source date in UTC, and so it follows that the - # correct transformation is calendar.timegm() - self.seconds = calendar.timegm(dt.utctimetuple()) - self.nanos = dt.microsecond * _NANOS_PER_MICROSECOND - - -class Duration(object): - """Class for Duration message type.""" - - __slots__ = () - - def ToJsonString(self): - """Converts Duration to string format. - - Returns: - A string converted from self. The string format will contains - 3, 6, or 9 fractional digits depending on the precision required to - represent the exact Duration value. For example: "1s", "1.010s", - "1.000000100s", "-3.100s" - """ - _CheckDurationValid(self.seconds, self.nanos) - if self.seconds < 0 or self.nanos < 0: - result = '-' - seconds = - self.seconds + int((0 - self.nanos) // 1e9) - nanos = (0 - self.nanos) % 1e9 - else: - result = '' - seconds = self.seconds + int(self.nanos // 1e9) - nanos = self.nanos % 1e9 - result += '%d' % seconds - if (nanos % 1e9) == 0: - # If there are 0 fractional digits, the fractional - # point '.' should be omitted when serializing. - return result + 's' - if (nanos % 1e6) == 0: - # Serialize 3 fractional digits. - return result + '.%03ds' % (nanos / 1e6) - if (nanos % 1e3) == 0: - # Serialize 6 fractional digits. - return result + '.%06ds' % (nanos / 1e3) - # Serialize 9 fractional digits. - return result + '.%09ds' % nanos - - def FromJsonString(self, value): - """Converts a string to Duration. - - Args: - value: A string to be converted. The string must end with 's'. Any - fractional digits (or none) are accepted as long as they fit into - precision. For example: "1s", "1.01s", "1.0000001s", "-3.100s - - Raises: - ValueError: On parsing problems. - """ - if not isinstance(value, str): - raise ValueError('Duration JSON value not a string: {!r}'.format(value)) - if len(value) < 1 or value[-1] != 's': - raise ValueError( - 'Duration must end with letter "s": {0}.'.format(value)) - try: - pos = value.find('.') - if pos == -1: - seconds = int(value[:-1]) - nanos = 0 - else: - seconds = int(value[:pos]) - if value[0] == '-': - nanos = int(round(float('-0{0}'.format(value[pos: -1])) *1e9)) - else: - nanos = int(round(float('0{0}'.format(value[pos: -1])) *1e9)) - _CheckDurationValid(seconds, nanos) - self.seconds = seconds - self.nanos = nanos - except ValueError as e: - raise ValueError( - 'Couldn\'t parse duration: {0} : {1}.'.format(value, e)) - - def ToNanoseconds(self): - """Converts a Duration to nanoseconds.""" - return self.seconds * _NANOS_PER_SECOND + self.nanos - - def ToMicroseconds(self): - """Converts a Duration to microseconds.""" - micros = _RoundTowardZero(self.nanos, _NANOS_PER_MICROSECOND) - return self.seconds * _MICROS_PER_SECOND + micros - - def ToMilliseconds(self): - """Converts a Duration to milliseconds.""" - millis = _RoundTowardZero(self.nanos, _NANOS_PER_MILLISECOND) - return self.seconds * _MILLIS_PER_SECOND + millis - - def ToSeconds(self): - """Converts a Duration to seconds.""" - return self.seconds - - def FromNanoseconds(self, nanos): - """Converts nanoseconds to Duration.""" - self._NormalizeDuration(nanos // _NANOS_PER_SECOND, - nanos % _NANOS_PER_SECOND) - - def FromMicroseconds(self, micros): - """Converts microseconds to Duration.""" - self._NormalizeDuration( - micros // _MICROS_PER_SECOND, - (micros % _MICROS_PER_SECOND) * _NANOS_PER_MICROSECOND) - - def FromMilliseconds(self, millis): - """Converts milliseconds to Duration.""" - self._NormalizeDuration( - millis // _MILLIS_PER_SECOND, - (millis % _MILLIS_PER_SECOND) * _NANOS_PER_MILLISECOND) - - def FromSeconds(self, seconds): - """Converts seconds to Duration.""" - self.seconds = seconds - self.nanos = 0 - - def ToTimedelta(self): - """Converts Duration to timedelta.""" - return datetime.timedelta( - seconds=self.seconds, microseconds=_RoundTowardZero( - self.nanos, _NANOS_PER_MICROSECOND)) - - def FromTimedelta(self, td): - """Converts timedelta to Duration.""" - self._NormalizeDuration(td.seconds + td.days * _SECONDS_PER_DAY, - td.microseconds * _NANOS_PER_MICROSECOND) - - def _NormalizeDuration(self, seconds, nanos): - """Set Duration by seconds and nanos.""" - # Force nanos to be negative if the duration is negative. - if seconds < 0 and nanos > 0: - seconds += 1 - nanos -= _NANOS_PER_SECOND - self.seconds = seconds - self.nanos = nanos - - -def _CheckDurationValid(seconds, nanos): - if seconds < -_DURATION_SECONDS_MAX or seconds > _DURATION_SECONDS_MAX: - raise ValueError( - 'Duration is not valid: Seconds {0} must be in range ' - '[-315576000000, 315576000000].'.format(seconds)) - if nanos <= -_NANOS_PER_SECOND or nanos >= _NANOS_PER_SECOND: - raise ValueError( - 'Duration is not valid: Nanos {0} must be in range ' - '[-999999999, 999999999].'.format(nanos)) - if (nanos < 0 and seconds > 0) or (nanos > 0 and seconds < 0): - raise ValueError( - 'Duration is not valid: Sign mismatch.') - - -def _RoundTowardZero(value, divider): - """Truncates the remainder part after division.""" - # For some languages, the sign of the remainder is implementation - # dependent if any of the operands is negative. Here we enforce - # "rounded toward zero" semantics. For example, for (-5) / 2 an - # implementation may give -3 as the result with the remainder being - # 1. This function ensures we always return -2 (closer to zero). - result = value // divider - remainder = value % divider - if result < 0 and remainder > 0: - return result + 1 - else: - return result - - -class FieldMask(object): - """Class for FieldMask message type.""" - - __slots__ = () - - def ToJsonString(self): - """Converts FieldMask to string according to proto3 JSON spec.""" - camelcase_paths = [] - for path in self.paths: - camelcase_paths.append(_SnakeCaseToCamelCase(path)) - return ','.join(camelcase_paths) - - def FromJsonString(self, value): - """Converts string to FieldMask according to proto3 JSON spec.""" - if not isinstance(value, str): - raise ValueError('FieldMask JSON value not a string: {!r}'.format(value)) - self.Clear() - if value: - for path in value.split(','): - self.paths.append(_CamelCaseToSnakeCase(path)) - - def IsValidForDescriptor(self, message_descriptor): - """Checks whether the FieldMask is valid for Message Descriptor.""" - for path in self.paths: - if not _IsValidPath(message_descriptor, path): - return False - return True - - def AllFieldsFromDescriptor(self, message_descriptor): - """Gets all direct fields of Message Descriptor to FieldMask.""" - self.Clear() - for field in message_descriptor.fields: - self.paths.append(field.name) - - def CanonicalFormFromMask(self, mask): - """Converts a FieldMask to the canonical form. - - Removes paths that are covered by another path. For example, - "foo.bar" is covered by "foo" and will be removed if "foo" - is also in the FieldMask. Then sorts all paths in alphabetical order. - - Args: - mask: The original FieldMask to be converted. - """ - tree = _FieldMaskTree(mask) - tree.ToFieldMask(self) - - def Union(self, mask1, mask2): - """Merges mask1 and mask2 into this FieldMask.""" - _CheckFieldMaskMessage(mask1) - _CheckFieldMaskMessage(mask2) - tree = _FieldMaskTree(mask1) - tree.MergeFromFieldMask(mask2) - tree.ToFieldMask(self) - - def Intersect(self, mask1, mask2): - """Intersects mask1 and mask2 into this FieldMask.""" - _CheckFieldMaskMessage(mask1) - _CheckFieldMaskMessage(mask2) - tree = _FieldMaskTree(mask1) - intersection = _FieldMaskTree() - for path in mask2.paths: - tree.IntersectPath(path, intersection) - intersection.ToFieldMask(self) - - def MergeMessage( - self, source, destination, - replace_message_field=False, replace_repeated_field=False): - """Merges fields specified in FieldMask from source to destination. - - Args: - source: Source message. - destination: The destination message to be merged into. - replace_message_field: Replace message field if True. Merge message - field if False. - replace_repeated_field: Replace repeated field if True. Append - elements of repeated field if False. - """ - tree = _FieldMaskTree(self) - tree.MergeMessage( - source, destination, replace_message_field, replace_repeated_field) - - -def _IsValidPath(message_descriptor, path): - """Checks whether the path is valid for Message Descriptor.""" - parts = path.split('.') - last = parts.pop() - for name in parts: - field = message_descriptor.fields_by_name.get(name) - if (field is None or - field.label == FieldDescriptor.LABEL_REPEATED or - field.type != FieldDescriptor.TYPE_MESSAGE): - return False - message_descriptor = field.message_type - return last in message_descriptor.fields_by_name - - -def _CheckFieldMaskMessage(message): - """Raises ValueError if message is not a FieldMask.""" - message_descriptor = message.DESCRIPTOR - if (message_descriptor.name != 'FieldMask' or - message_descriptor.file.name != 'google/protobuf/field_mask.proto'): - raise ValueError('Message {0} is not a FieldMask.'.format( - message_descriptor.full_name)) - - -def _SnakeCaseToCamelCase(path_name): - """Converts a path name from snake_case to camelCase.""" - result = [] - after_underscore = False - for c in path_name: - if c.isupper(): - raise ValueError( - 'Fail to print FieldMask to Json string: Path name ' - '{0} must not contain uppercase letters.'.format(path_name)) - if after_underscore: - if c.islower(): - result.append(c.upper()) - after_underscore = False - else: - raise ValueError( - 'Fail to print FieldMask to Json string: The ' - 'character after a "_" must be a lowercase letter ' - 'in path name {0}.'.format(path_name)) - elif c == '_': - after_underscore = True - else: - result += c - - if after_underscore: - raise ValueError('Fail to print FieldMask to Json string: Trailing "_" ' - 'in path name {0}.'.format(path_name)) - return ''.join(result) - - -def _CamelCaseToSnakeCase(path_name): - """Converts a field name from camelCase to snake_case.""" - result = [] - for c in path_name: - if c == '_': - raise ValueError('Fail to parse FieldMask: Path name ' - '{0} must not contain "_"s.'.format(path_name)) - if c.isupper(): - result += '_' - result += c.lower() - else: - result += c - return ''.join(result) - - -class _FieldMaskTree(object): - """Represents a FieldMask in a tree structure. - - For example, given a FieldMask "foo.bar,foo.baz,bar.baz", - the FieldMaskTree will be: - [_root] -+- foo -+- bar - | | - | +- baz - | - +- bar --- baz - In the tree, each leaf node represents a field path. - """ - - __slots__ = ('_root',) - - def __init__(self, field_mask=None): - """Initializes the tree by FieldMask.""" - self._root = {} - if field_mask: - self.MergeFromFieldMask(field_mask) - - def MergeFromFieldMask(self, field_mask): - """Merges a FieldMask to the tree.""" - for path in field_mask.paths: - self.AddPath(path) - - def AddPath(self, path): - """Adds a field path into the tree. - - If the field path to add is a sub-path of an existing field path - in the tree (i.e., a leaf node), it means the tree already matches - the given path so nothing will be added to the tree. If the path - matches an existing non-leaf node in the tree, that non-leaf node - will be turned into a leaf node with all its children removed because - the path matches all the node's children. Otherwise, a new path will - be added. - - Args: - path: The field path to add. - """ - node = self._root - for name in path.split('.'): - if name not in node: - node[name] = {} - elif not node[name]: - # Pre-existing empty node implies we already have this entire tree. - return - node = node[name] - # Remove any sub-trees we might have had. - node.clear() - - def ToFieldMask(self, field_mask): - """Converts the tree to a FieldMask.""" - field_mask.Clear() - _AddFieldPaths(self._root, '', field_mask) - - def IntersectPath(self, path, intersection): - """Calculates the intersection part of a field path with this tree. - - Args: - path: The field path to calculates. - intersection: The out tree to record the intersection part. - """ - node = self._root - for name in path.split('.'): - if name not in node: - return - elif not node[name]: - intersection.AddPath(path) - return - node = node[name] - intersection.AddLeafNodes(path, node) - - def AddLeafNodes(self, prefix, node): - """Adds leaf nodes begin with prefix to this tree.""" - if not node: - self.AddPath(prefix) - for name in node: - child_path = prefix + '.' + name - self.AddLeafNodes(child_path, node[name]) - - def MergeMessage( - self, source, destination, - replace_message, replace_repeated): - """Merge all fields specified by this tree from source to destination.""" - _MergeMessage( - self._root, source, destination, replace_message, replace_repeated) - - -def _StrConvert(value): - """Converts value to str if it is not.""" - # This file is imported by c extension and some methods like ClearField - # requires string for the field name. py2/py3 has different text - # type and may use unicode. - if not isinstance(value, str): - return value.encode('utf-8') - return value - - -def _MergeMessage( - node, source, destination, replace_message, replace_repeated): - """Merge all fields specified by a sub-tree from source to destination.""" - source_descriptor = source.DESCRIPTOR - for name in node: - child = node[name] - field = source_descriptor.fields_by_name[name] - if field is None: - raise ValueError('Error: Can\'t find field {0} in message {1}.'.format( - name, source_descriptor.full_name)) - if child: - # Sub-paths are only allowed for singular message fields. - if (field.label == FieldDescriptor.LABEL_REPEATED or - field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE): - raise ValueError('Error: Field {0} in message {1} is not a singular ' - 'message field and cannot have sub-fields.'.format( - name, source_descriptor.full_name)) - if source.HasField(name): - _MergeMessage( - child, getattr(source, name), getattr(destination, name), - replace_message, replace_repeated) - continue - if field.label == FieldDescriptor.LABEL_REPEATED: - if replace_repeated: - destination.ClearField(_StrConvert(name)) - repeated_source = getattr(source, name) - repeated_destination = getattr(destination, name) - repeated_destination.MergeFrom(repeated_source) - else: - if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE: - if replace_message: - destination.ClearField(_StrConvert(name)) - if source.HasField(name): - getattr(destination, name).MergeFrom(getattr(source, name)) - else: - setattr(destination, name, getattr(source, name)) - - -def _AddFieldPaths(node, prefix, field_mask): - """Adds the field paths descended from node to field_mask.""" - if not node and prefix: - field_mask.paths.append(prefix) - return - for name in sorted(node): - if prefix: - child_path = prefix + '.' + name - else: - child_path = name - _AddFieldPaths(node[name], child_path, field_mask) - - -def _SetStructValue(struct_value, value): - if value is None: - struct_value.null_value = 0 - elif isinstance(value, bool): - # Note: this check must come before the number check because in Python - # True and False are also considered numbers. - struct_value.bool_value = value - elif isinstance(value, str): - struct_value.string_value = value - elif isinstance(value, (int, float)): - struct_value.number_value = value - elif isinstance(value, (dict, Struct)): - struct_value.struct_value.Clear() - struct_value.struct_value.update(value) - elif isinstance(value, (list, ListValue)): - struct_value.list_value.Clear() - struct_value.list_value.extend(value) - else: - raise ValueError('Unexpected type') - - -def _GetStructValue(struct_value): - which = struct_value.WhichOneof('kind') - if which == 'struct_value': - return struct_value.struct_value - elif which == 'null_value': - return None - elif which == 'number_value': - return struct_value.number_value - elif which == 'string_value': - return struct_value.string_value - elif which == 'bool_value': - return struct_value.bool_value - elif which == 'list_value': - return struct_value.list_value - elif which is None: - raise ValueError('Value not set') - - -class Struct(object): - """Class for Struct message type.""" - - __slots__ = () - - def __getitem__(self, key): - return _GetStructValue(self.fields[key]) - - def __contains__(self, item): - return item in self.fields - - def __setitem__(self, key, value): - _SetStructValue(self.fields[key], value) - - def __delitem__(self, key): - del self.fields[key] - - def __len__(self): - return len(self.fields) - - def __iter__(self): - return iter(self.fields) - - def keys(self): # pylint: disable=invalid-name - return self.fields.keys() - - def values(self): # pylint: disable=invalid-name - return [self[key] for key in self] - - def items(self): # pylint: disable=invalid-name - return [(key, self[key]) for key in self] - - def get_or_create_list(self, key): - """Returns a list for this key, creating if it didn't exist already.""" - if not self.fields[key].HasField('list_value'): - # Clear will mark list_value modified which will indeed create a list. - self.fields[key].list_value.Clear() - return self.fields[key].list_value - - def get_or_create_struct(self, key): - """Returns a struct for this key, creating if it didn't exist already.""" - if not self.fields[key].HasField('struct_value'): - # Clear will mark struct_value modified which will indeed create a struct. - self.fields[key].struct_value.Clear() - return self.fields[key].struct_value - - def update(self, dictionary): # pylint: disable=invalid-name - for key, value in dictionary.items(): - _SetStructValue(self.fields[key], value) - -collections.abc.MutableMapping.register(Struct) - - -class ListValue(object): - """Class for ListValue message type.""" - - __slots__ = () - - def __len__(self): - return len(self.values) - - def append(self, value): - _SetStructValue(self.values.add(), value) - - def extend(self, elem_seq): - for value in elem_seq: - self.append(value) - - def __getitem__(self, index): - """Retrieves item by the specified index.""" - return _GetStructValue(self.values.__getitem__(index)) - - def __setitem__(self, index, value): - _SetStructValue(self.values.__getitem__(index), value) - - def __delitem__(self, key): - del self.values[key] - - def items(self): - for i in range(len(self)): - yield self[i] - - def add_struct(self): - """Appends and returns a struct value as the next value in the list.""" - struct_value = self.values.add().struct_value - # Clear will mark struct_value modified which will indeed create a struct. - struct_value.Clear() - return struct_value - - def add_list(self): - """Appends and returns a list value as the next value in the list.""" - list_value = self.values.add().list_value - # Clear will mark list_value modified which will indeed create a list. - list_value.Clear() - return list_value - -collections.abc.MutableSequence.register(ListValue) - - -WKTBASES = { - 'google.protobuf.Any': Any, - 'google.protobuf.Duration': Duration, - 'google.protobuf.FieldMask': FieldMask, - 'google.protobuf.ListValue': ListValue, - 'google.protobuf.Struct': Struct, - 'google.protobuf.Timestamp': Timestamp, -} diff --git a/scripts/protobuf3/protobuf3/internal/wire_format.py b/scripts/protobuf3/protobuf3/internal/wire_format.py deleted file mode 100644 index 883f525..0000000 --- a/scripts/protobuf3/protobuf3/internal/wire_format.py +++ /dev/null @@ -1,268 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Constants and static functions to support protocol buffer wire format.""" - -__author__ = 'robinson@google.com (Will Robinson)' - -import struct -from google.protobuf import descriptor -from google.protobuf import message - - -TAG_TYPE_BITS = 3 # Number of bits used to hold type info in a proto tag. -TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1 # 0x7 - -# These numbers identify the wire type of a protocol buffer value. -# We use the least-significant TAG_TYPE_BITS bits of the varint-encoded -# tag-and-type to store one of these WIRETYPE_* constants. -# These values must match WireType enum in google/protobuf/wire_format.h. -WIRETYPE_VARINT = 0 -WIRETYPE_FIXED64 = 1 -WIRETYPE_LENGTH_DELIMITED = 2 -WIRETYPE_START_GROUP = 3 -WIRETYPE_END_GROUP = 4 -WIRETYPE_FIXED32 = 5 -_WIRETYPE_MAX = 5 - - -# Bounds for various integer types. -INT32_MAX = int((1 << 31) - 1) -INT32_MIN = int(-(1 << 31)) -UINT32_MAX = (1 << 32) - 1 - -INT64_MAX = (1 << 63) - 1 -INT64_MIN = -(1 << 63) -UINT64_MAX = (1 << 64) - 1 - -# "struct" format strings that will encode/decode the specified formats. -FORMAT_UINT32_LITTLE_ENDIAN = '> TAG_TYPE_BITS), (tag & TAG_TYPE_MASK) - - -def ZigZagEncode(value): - """ZigZag Transform: Encodes signed integers so that they can be - effectively used with varint encoding. See wire_format.h for - more details. - """ - if value >= 0: - return value << 1 - return (value << 1) ^ (~0) - - -def ZigZagDecode(value): - """Inverse of ZigZagEncode().""" - if not value & 0x1: - return value >> 1 - return (value >> 1) ^ (~0) - - - -# The *ByteSize() functions below return the number of bytes required to -# serialize "field number + type" information and then serialize the value. - - -def Int32ByteSize(field_number, int32): - return Int64ByteSize(field_number, int32) - - -def Int32ByteSizeNoTag(int32): - return _VarUInt64ByteSizeNoTag(0xffffffffffffffff & int32) - - -def Int64ByteSize(field_number, int64): - # Have to convert to uint before calling UInt64ByteSize(). - return UInt64ByteSize(field_number, 0xffffffffffffffff & int64) - - -def UInt32ByteSize(field_number, uint32): - return UInt64ByteSize(field_number, uint32) - - -def UInt64ByteSize(field_number, uint64): - return TagByteSize(field_number) + _VarUInt64ByteSizeNoTag(uint64) - - -def SInt32ByteSize(field_number, int32): - return UInt32ByteSize(field_number, ZigZagEncode(int32)) - - -def SInt64ByteSize(field_number, int64): - return UInt64ByteSize(field_number, ZigZagEncode(int64)) - - -def Fixed32ByteSize(field_number, fixed32): - return TagByteSize(field_number) + 4 - - -def Fixed64ByteSize(field_number, fixed64): - return TagByteSize(field_number) + 8 - - -def SFixed32ByteSize(field_number, sfixed32): - return TagByteSize(field_number) + 4 - - -def SFixed64ByteSize(field_number, sfixed64): - return TagByteSize(field_number) + 8 - - -def FloatByteSize(field_number, flt): - return TagByteSize(field_number) + 4 - - -def DoubleByteSize(field_number, double): - return TagByteSize(field_number) + 8 - - -def BoolByteSize(field_number, b): - return TagByteSize(field_number) + 1 - - -def EnumByteSize(field_number, enum): - return UInt32ByteSize(field_number, enum) - - -def StringByteSize(field_number, string): - return BytesByteSize(field_number, string.encode('utf-8')) - - -def BytesByteSize(field_number, b): - return (TagByteSize(field_number) - + _VarUInt64ByteSizeNoTag(len(b)) - + len(b)) - - -def GroupByteSize(field_number, message): - return (2 * TagByteSize(field_number) # START and END group. - + message.ByteSize()) - - -def MessageByteSize(field_number, message): - return (TagByteSize(field_number) - + _VarUInt64ByteSizeNoTag(message.ByteSize()) - + message.ByteSize()) - - -def MessageSetItemByteSize(field_number, msg): - # First compute the sizes of the tags. - # There are 2 tags for the beginning and ending of the repeated group, that - # is field number 1, one with field number 2 (type_id) and one with field - # number 3 (message). - total_size = (2 * TagByteSize(1) + TagByteSize(2) + TagByteSize(3)) - - # Add the number of bytes for type_id. - total_size += _VarUInt64ByteSizeNoTag(field_number) - - message_size = msg.ByteSize() - - # The number of bytes for encoding the length of the message. - total_size += _VarUInt64ByteSizeNoTag(message_size) - - # The size of the message. - total_size += message_size - return total_size - - -def TagByteSize(field_number): - """Returns the bytes required to serialize a tag with this field number.""" - # Just pass in type 0, since the type won't affect the tag+type size. - return _VarUInt64ByteSizeNoTag(PackTag(field_number, 0)) - - -# Private helper function for the *ByteSize() functions above. - -def _VarUInt64ByteSizeNoTag(uint64): - """Returns the number of bytes required to serialize a single varint - using boundary value comparisons. (unrolled loop optimization -WPierce) - uint64 must be unsigned. - """ - if uint64 <= 0x7f: return 1 - if uint64 <= 0x3fff: return 2 - if uint64 <= 0x1fffff: return 3 - if uint64 <= 0xfffffff: return 4 - if uint64 <= 0x7ffffffff: return 5 - if uint64 <= 0x3ffffffffff: return 6 - if uint64 <= 0x1ffffffffffff: return 7 - if uint64 <= 0xffffffffffffff: return 8 - if uint64 <= 0x7fffffffffffffff: return 9 - if uint64 > UINT64_MAX: - raise message.EncodeError('Value out of range: %d' % uint64) - return 10 - - -NON_PACKABLE_TYPES = ( - descriptor.FieldDescriptor.TYPE_STRING, - descriptor.FieldDescriptor.TYPE_GROUP, - descriptor.FieldDescriptor.TYPE_MESSAGE, - descriptor.FieldDescriptor.TYPE_BYTES -) - - -def IsTypePackable(field_type): - """Return true iff packable = true is valid for fields of this type. - - Args: - field_type: a FieldDescriptor::Type value. - - Returns: - True iff fields of this type are packable. - """ - return field_type not in NON_PACKABLE_TYPES diff --git a/scripts/protobuf3/protobuf3/json_format.py b/scripts/protobuf3/protobuf3/json_format.py deleted file mode 100644 index 5024ed8..0000000 --- a/scripts/protobuf3/protobuf3/json_format.py +++ /dev/null @@ -1,912 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Contains routines for printing protocol messages in JSON format. - -Simple usage example: - - # Create a proto object and serialize it to a json format string. - message = my_proto_pb2.MyMessage(foo='bar') - json_string = json_format.MessageToJson(message) - - # Parse a json format string to proto object. - message = json_format.Parse(json_string, my_proto_pb2.MyMessage()) -""" - -__author__ = 'jieluo@google.com (Jie Luo)' - - -import base64 -from collections import OrderedDict -import json -import math -from operator import methodcaller -import re -import sys - -from google.protobuf.internal import type_checkers -from google.protobuf import descriptor -from google.protobuf import symbol_database - - -_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S' -_INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32, - descriptor.FieldDescriptor.CPPTYPE_UINT32, - descriptor.FieldDescriptor.CPPTYPE_INT64, - descriptor.FieldDescriptor.CPPTYPE_UINT64]) -_INT64_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT64, - descriptor.FieldDescriptor.CPPTYPE_UINT64]) -_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT, - descriptor.FieldDescriptor.CPPTYPE_DOUBLE]) -_INFINITY = 'Infinity' -_NEG_INFINITY = '-Infinity' -_NAN = 'NaN' - -_UNPAIRED_SURROGATE_PATTERN = re.compile( - u'[\ud800-\udbff](?![\udc00-\udfff])|(? self.max_recursion_depth: - raise ParseError('Message too deep. Max recursion depth is {0}'.format( - self.max_recursion_depth)) - message_descriptor = message.DESCRIPTOR - full_name = message_descriptor.full_name - if not path: - path = message_descriptor.name - if _IsWrapperMessage(message_descriptor): - self._ConvertWrapperMessage(value, message, path) - elif full_name in _WKTJSONMETHODS: - methodcaller(_WKTJSONMETHODS[full_name][1], value, message, path)(self) - else: - self._ConvertFieldValuePair(value, message, path) - self.recursion_depth -= 1 - - def _ConvertFieldValuePair(self, js, message, path): - """Convert field value pairs into regular message. - - Args: - js: A JSON object to convert the field value pairs. - message: A regular protocol message to record the data. - path: parent path to log parse error info. - - Raises: - ParseError: In case of problems converting. - """ - names = [] - message_descriptor = message.DESCRIPTOR - fields_by_json_name = dict((f.json_name, f) - for f in message_descriptor.fields) - for name in js: - try: - field = fields_by_json_name.get(name, None) - if not field: - field = message_descriptor.fields_by_name.get(name, None) - if not field and _VALID_EXTENSION_NAME.match(name): - if not message_descriptor.is_extendable: - raise ParseError( - 'Message type {0} does not have extensions at {1}'.format( - message_descriptor.full_name, path)) - identifier = name[1:-1] # strip [] brackets - # pylint: disable=protected-access - field = message.Extensions._FindExtensionByName(identifier) - # pylint: enable=protected-access - if not field: - # Try looking for extension by the message type name, dropping the - # field name following the final . separator in full_name. - identifier = '.'.join(identifier.split('.')[:-1]) - # pylint: disable=protected-access - field = message.Extensions._FindExtensionByName(identifier) - # pylint: enable=protected-access - if not field: - if self.ignore_unknown_fields: - continue - raise ParseError( - ('Message type "{0}" has no field named "{1}" at "{2}".\n' - ' Available Fields(except extensions): "{3}"').format( - message_descriptor.full_name, name, path, - [f.json_name for f in message_descriptor.fields])) - if name in names: - raise ParseError('Message type "{0}" should not have multiple ' - '"{1}" fields at "{2}".'.format( - message.DESCRIPTOR.full_name, name, path)) - names.append(name) - value = js[name] - # Check no other oneof field is parsed. - if field.containing_oneof is not None and value is not None: - oneof_name = field.containing_oneof.name - if oneof_name in names: - raise ParseError('Message type "{0}" should not have multiple ' - '"{1}" oneof fields at "{2}".'.format( - message.DESCRIPTOR.full_name, oneof_name, - path)) - names.append(oneof_name) - - if value is None: - if (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE - and field.message_type.full_name == 'google.protobuf.Value'): - sub_message = getattr(message, field.name) - sub_message.null_value = 0 - elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM - and field.enum_type.full_name == 'google.protobuf.NullValue'): - setattr(message, field.name, 0) - else: - message.ClearField(field.name) - continue - - # Parse field value. - if _IsMapEntry(field): - message.ClearField(field.name) - self._ConvertMapFieldValue(value, message, field, - '{0}.{1}'.format(path, name)) - elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - message.ClearField(field.name) - if not isinstance(value, list): - raise ParseError('repeated field {0} must be in [] which is ' - '{1} at {2}'.format(name, value, path)) - if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - # Repeated message field. - for index, item in enumerate(value): - sub_message = getattr(message, field.name).add() - # None is a null_value in Value. - if (item is None and - sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'): - raise ParseError('null is not allowed to be used as an element' - ' in a repeated field at {0}.{1}[{2}]'.format( - path, name, index)) - self.ConvertMessage(item, sub_message, - '{0}.{1}[{2}]'.format(path, name, index)) - else: - # Repeated scalar field. - for index, item in enumerate(value): - if item is None: - raise ParseError('null is not allowed to be used as an element' - ' in a repeated field at {0}.{1}[{2}]'.format( - path, name, index)) - getattr(message, field.name).append( - _ConvertScalarFieldValue( - item, field, '{0}.{1}[{2}]'.format(path, name, index))) - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - if field.is_extension: - sub_message = message.Extensions[field] - else: - sub_message = getattr(message, field.name) - sub_message.SetInParent() - self.ConvertMessage(value, sub_message, '{0}.{1}'.format(path, name)) - else: - if field.is_extension: - message.Extensions[field] = _ConvertScalarFieldValue( - value, field, '{0}.{1}'.format(path, name)) - else: - setattr( - message, field.name, - _ConvertScalarFieldValue(value, field, - '{0}.{1}'.format(path, name))) - except ParseError as e: - if field and field.containing_oneof is None: - raise ParseError('Failed to parse {0} field: {1}.'.format(name, e)) - else: - raise ParseError(str(e)) - except ValueError as e: - raise ParseError('Failed to parse {0} field: {1}.'.format(name, e)) - except TypeError as e: - raise ParseError('Failed to parse {0} field: {1}.'.format(name, e)) - - def _ConvertAnyMessage(self, value, message, path): - """Convert a JSON representation into Any message.""" - if isinstance(value, dict) and not value: - return - try: - type_url = value['@type'] - except KeyError: - raise ParseError( - '@type is missing when parsing any message at {0}'.format(path)) - - try: - sub_message = _CreateMessageFromTypeUrl(type_url, self.descriptor_pool) - except TypeError as e: - raise ParseError('{0} at {1}'.format(e, path)) - message_descriptor = sub_message.DESCRIPTOR - full_name = message_descriptor.full_name - if _IsWrapperMessage(message_descriptor): - self._ConvertWrapperMessage(value['value'], sub_message, - '{0}.value'.format(path)) - elif full_name in _WKTJSONMETHODS: - methodcaller(_WKTJSONMETHODS[full_name][1], value['value'], sub_message, - '{0}.value'.format(path))( - self) - else: - del value['@type'] - self._ConvertFieldValuePair(value, sub_message, path) - value['@type'] = type_url - # Sets Any message - message.value = sub_message.SerializeToString() - message.type_url = type_url - - def _ConvertGenericMessage(self, value, message, path): - """Convert a JSON representation into message with FromJsonString.""" - # Duration, Timestamp, FieldMask have a FromJsonString method to do the - # conversion. Users can also call the method directly. - try: - message.FromJsonString(value) - except ValueError as e: - raise ParseError('{0} at {1}'.format(e, path)) - - def _ConvertValueMessage(self, value, message, path): - """Convert a JSON representation into Value message.""" - if isinstance(value, dict): - self._ConvertStructMessage(value, message.struct_value, path) - elif isinstance(value, list): - self._ConvertListValueMessage(value, message.list_value, path) - elif value is None: - message.null_value = 0 - elif isinstance(value, bool): - message.bool_value = value - elif isinstance(value, str): - message.string_value = value - elif isinstance(value, _INT_OR_FLOAT): - message.number_value = value - else: - raise ParseError('Value {0} has unexpected type {1} at {2}'.format( - value, type(value), path)) - - def _ConvertListValueMessage(self, value, message, path): - """Convert a JSON representation into ListValue message.""" - if not isinstance(value, list): - raise ParseError('ListValue must be in [] which is {0} at {1}'.format( - value, path)) - message.ClearField('values') - for index, item in enumerate(value): - self._ConvertValueMessage(item, message.values.add(), - '{0}[{1}]'.format(path, index)) - - def _ConvertStructMessage(self, value, message, path): - """Convert a JSON representation into Struct message.""" - if not isinstance(value, dict): - raise ParseError('Struct must be in a dict which is {0} at {1}'.format( - value, path)) - # Clear will mark the struct as modified so it will be created even if - # there are no values. - message.Clear() - for key in value: - self._ConvertValueMessage(value[key], message.fields[key], - '{0}.{1}'.format(path, key)) - return - - def _ConvertWrapperMessage(self, value, message, path): - """Convert a JSON representation into Wrapper message.""" - field = message.DESCRIPTOR.fields_by_name['value'] - setattr( - message, 'value', - _ConvertScalarFieldValue(value, field, path='{0}.value'.format(path))) - - def _ConvertMapFieldValue(self, value, message, field, path): - """Convert map field value for a message map field. - - Args: - value: A JSON object to convert the map field value. - message: A protocol message to record the converted data. - field: The descriptor of the map field to be converted. - path: parent path to log parse error info. - - Raises: - ParseError: In case of convert problems. - """ - if not isinstance(value, dict): - raise ParseError( - 'Map field {0} must be in a dict which is {1} at {2}'.format( - field.name, value, path)) - key_field = field.message_type.fields_by_name['key'] - value_field = field.message_type.fields_by_name['value'] - for key in value: - key_value = _ConvertScalarFieldValue(key, key_field, - '{0}.key'.format(path), True) - if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - self.ConvertMessage(value[key], - getattr(message, field.name)[key_value], - '{0}[{1}]'.format(path, key_value)) - else: - getattr(message, field.name)[key_value] = _ConvertScalarFieldValue( - value[key], value_field, path='{0}[{1}]'.format(path, key_value)) - - -def _ConvertScalarFieldValue(value, field, path, require_str=False): - """Convert a single scalar field value. - - Args: - value: A scalar value to convert the scalar field value. - field: The descriptor of the field to convert. - path: parent path to log parse error info. - require_str: If True, the field value must be a str. - - Returns: - The converted scalar field value - - Raises: - ParseError: In case of convert problems. - """ - try: - if field.cpp_type in _INT_TYPES: - return _ConvertInteger(value) - elif field.cpp_type in _FLOAT_TYPES: - return _ConvertFloat(value, field) - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: - return _ConvertBool(value, require_str) - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: - if field.type == descriptor.FieldDescriptor.TYPE_BYTES: - if isinstance(value, str): - encoded = value.encode('utf-8') - else: - encoded = value - # Add extra padding '=' - padded_value = encoded + b'=' * (4 - len(encoded) % 4) - return base64.urlsafe_b64decode(padded_value) - else: - # Checking for unpaired surrogates appears to be unreliable, - # depending on the specific Python version, so we check manually. - if _UNPAIRED_SURROGATE_PATTERN.search(value): - raise ParseError('Unpaired surrogate') - return value - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: - # Convert an enum value. - enum_value = field.enum_type.values_by_name.get(value, None) - if enum_value is None: - try: - number = int(value) - enum_value = field.enum_type.values_by_number.get(number, None) - except ValueError: - raise ParseError('Invalid enum value {0} for enum type {1}'.format( - value, field.enum_type.full_name)) - if enum_value is None: - if field.file.syntax == 'proto3': - # Proto3 accepts unknown enums. - return number - raise ParseError('Invalid enum value {0} for enum type {1}'.format( - value, field.enum_type.full_name)) - return enum_value.number - except ParseError as e: - raise ParseError('{0} at {1}'.format(e, path)) - - -def _ConvertInteger(value): - """Convert an integer. - - Args: - value: A scalar value to convert. - - Returns: - The integer value. - - Raises: - ParseError: If an integer couldn't be consumed. - """ - if isinstance(value, float) and not value.is_integer(): - raise ParseError('Couldn\'t parse integer: {0}'.format(value)) - - if isinstance(value, str) and value.find(' ') != -1: - raise ParseError('Couldn\'t parse integer: "{0}"'.format(value)) - - if isinstance(value, bool): - raise ParseError('Bool value {0} is not acceptable for ' - 'integer field'.format(value)) - - return int(value) - - -def _ConvertFloat(value, field): - """Convert an floating point number.""" - if isinstance(value, float): - if math.isnan(value): - raise ParseError('Couldn\'t parse NaN, use quoted "NaN" instead') - if math.isinf(value): - if value > 0: - raise ParseError('Couldn\'t parse Infinity or value too large, ' - 'use quoted "Infinity" instead') - else: - raise ParseError('Couldn\'t parse -Infinity or value too small, ' - 'use quoted "-Infinity" instead') - if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT: - # pylint: disable=protected-access - if value > type_checkers._FLOAT_MAX: - raise ParseError('Float value too large') - # pylint: disable=protected-access - if value < type_checkers._FLOAT_MIN: - raise ParseError('Float value too small') - if value == 'nan': - raise ParseError('Couldn\'t parse float "nan", use "NaN" instead') - try: - # Assume Python compatible syntax. - return float(value) - except ValueError: - # Check alternative spellings. - if value == _NEG_INFINITY: - return float('-inf') - elif value == _INFINITY: - return float('inf') - elif value == _NAN: - return float('nan') - else: - raise ParseError('Couldn\'t parse float: {0}'.format(value)) - - -def _ConvertBool(value, require_str): - """Convert a boolean value. - - Args: - value: A scalar value to convert. - require_str: If True, value must be a str. - - Returns: - The bool parsed. - - Raises: - ParseError: If a boolean value couldn't be consumed. - """ - if require_str: - if value == 'true': - return True - elif value == 'false': - return False - else: - raise ParseError('Expected "true" or "false", not {0}'.format(value)) - - if not isinstance(value, bool): - raise ParseError('Expected true or false without quotes') - return value - -_WKTJSONMETHODS = { - 'google.protobuf.Any': ['_AnyMessageToJsonObject', - '_ConvertAnyMessage'], - 'google.protobuf.Duration': ['_GenericMessageToJsonObject', - '_ConvertGenericMessage'], - 'google.protobuf.FieldMask': ['_GenericMessageToJsonObject', - '_ConvertGenericMessage'], - 'google.protobuf.ListValue': ['_ListValueMessageToJsonObject', - '_ConvertListValueMessage'], - 'google.protobuf.Struct': ['_StructMessageToJsonObject', - '_ConvertStructMessage'], - 'google.protobuf.Timestamp': ['_GenericMessageToJsonObject', - '_ConvertGenericMessage'], - 'google.protobuf.Value': ['_ValueMessageToJsonObject', - '_ConvertValueMessage'] -} diff --git a/scripts/protobuf3/protobuf3/message.py b/scripts/protobuf3/protobuf3/message.py deleted file mode 100644 index 76c6802..0000000 --- a/scripts/protobuf3/protobuf3/message.py +++ /dev/null @@ -1,424 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# TODO(robinson): We should just make these methods all "pure-virtual" and move -# all implementation out, into reflection.py for now. - - -"""Contains an abstract base class for protocol messages.""" - -__author__ = 'robinson@google.com (Will Robinson)' - -class Error(Exception): - """Base error type for this module.""" - pass - - -class DecodeError(Error): - """Exception raised when deserializing messages.""" - pass - - -class EncodeError(Error): - """Exception raised when serializing messages.""" - pass - - -class Message(object): - - """Abstract base class for protocol messages. - - Protocol message classes are almost always generated by the protocol - compiler. These generated types subclass Message and implement the methods - shown below. - """ - - # TODO(robinson): Link to an HTML document here. - - # TODO(robinson): Document that instances of this class will also - # have an Extensions attribute with __getitem__ and __setitem__. - # Again, not sure how to best convey this. - - # TODO(robinson): Document that the class must also have a static - # RegisterExtension(extension_field) method. - # Not sure how to best express at this point. - - # TODO(robinson): Document these fields and methods. - - __slots__ = [] - - #: The :class:`google.protobuf.descriptor.Descriptor` for this message type. - DESCRIPTOR = None - - def __deepcopy__(self, memo=None): - clone = type(self)() - clone.MergeFrom(self) - return clone - - def __eq__(self, other_msg): - """Recursively compares two messages by value and structure.""" - raise NotImplementedError - - def __ne__(self, other_msg): - # Can't just say self != other_msg, since that would infinitely recurse. :) - return not self == other_msg - - def __hash__(self): - raise TypeError('unhashable object') - - def __str__(self): - """Outputs a human-readable representation of the message.""" - raise NotImplementedError - - def __unicode__(self): - """Outputs a human-readable representation of the message.""" - raise NotImplementedError - - def MergeFrom(self, other_msg): - """Merges the contents of the specified message into current message. - - This method merges the contents of the specified message into the current - message. Singular fields that are set in the specified message overwrite - the corresponding fields in the current message. Repeated fields are - appended. Singular sub-messages and groups are recursively merged. - - Args: - other_msg (Message): A message to merge into the current message. - """ - raise NotImplementedError - - def CopyFrom(self, other_msg): - """Copies the content of the specified message into the current message. - - The method clears the current message and then merges the specified - message using MergeFrom. - - Args: - other_msg (Message): A message to copy into the current one. - """ - if self is other_msg: - return - self.Clear() - self.MergeFrom(other_msg) - - def Clear(self): - """Clears all data that was set in the message.""" - raise NotImplementedError - - def SetInParent(self): - """Mark this as present in the parent. - - This normally happens automatically when you assign a field of a - sub-message, but sometimes you want to make the sub-message - present while keeping it empty. If you find yourself using this, - you may want to reconsider your design. - """ - raise NotImplementedError - - def IsInitialized(self): - """Checks if the message is initialized. - - Returns: - bool: The method returns True if the message is initialized (i.e. all of - its required fields are set). - """ - raise NotImplementedError - - # TODO(robinson): MergeFromString() should probably return None and be - # implemented in terms of a helper that returns the # of bytes read. Our - # deserialization routines would use the helper when recursively - # deserializing, but the end user would almost always just want the no-return - # MergeFromString(). - - def MergeFromString(self, serialized): - """Merges serialized protocol buffer data into this message. - - When we find a field in `serialized` that is already present - in this message: - - - If it's a "repeated" field, we append to the end of our list. - - Else, if it's a scalar, we overwrite our field. - - Else, (it's a nonrepeated composite), we recursively merge - into the existing composite. - - Args: - serialized (bytes): Any object that allows us to call - ``memoryview(serialized)`` to access a string of bytes using the - buffer interface. - - Returns: - int: The number of bytes read from `serialized`. - For non-group messages, this will always be `len(serialized)`, - but for messages which are actually groups, this will - generally be less than `len(serialized)`, since we must - stop when we reach an ``END_GROUP`` tag. Note that if - we *do* stop because of an ``END_GROUP`` tag, the number - of bytes returned does not include the bytes - for the ``END_GROUP`` tag information. - - Raises: - DecodeError: if the input cannot be parsed. - """ - # TODO(robinson): Document handling of unknown fields. - # TODO(robinson): When we switch to a helper, this will return None. - raise NotImplementedError - - def ParseFromString(self, serialized): - """Parse serialized protocol buffer data into this message. - - Like :func:`MergeFromString()`, except we clear the object first. - - Raises: - message.DecodeError if the input cannot be parsed. - """ - self.Clear() - return self.MergeFromString(serialized) - - def SerializeToString(self, **kwargs): - """Serializes the protocol message to a binary string. - - Keyword Args: - deterministic (bool): If true, requests deterministic serialization - of the protobuf, with predictable ordering of map keys. - - Returns: - A binary string representation of the message if all of the required - fields in the message are set (i.e. the message is initialized). - - Raises: - EncodeError: if the message isn't initialized (see :func:`IsInitialized`). - """ - raise NotImplementedError - - def SerializePartialToString(self, **kwargs): - """Serializes the protocol message to a binary string. - - This method is similar to SerializeToString but doesn't check if the - message is initialized. - - Keyword Args: - deterministic (bool): If true, requests deterministic serialization - of the protobuf, with predictable ordering of map keys. - - Returns: - bytes: A serialized representation of the partial message. - """ - raise NotImplementedError - - # TODO(robinson): Decide whether we like these better - # than auto-generated has_foo() and clear_foo() methods - # on the instances themselves. This way is less consistent - # with C++, but it makes reflection-type access easier and - # reduces the number of magically autogenerated things. - # - # TODO(robinson): Be sure to document (and test) exactly - # which field names are accepted here. Are we case-sensitive? - # What do we do with fields that share names with Python keywords - # like 'lambda' and 'yield'? - # - # nnorwitz says: - # """ - # Typically (in python), an underscore is appended to names that are - # keywords. So they would become lambda_ or yield_. - # """ - def ListFields(self): - """Returns a list of (FieldDescriptor, value) tuples for present fields. - - A message field is non-empty if HasField() would return true. A singular - primitive field is non-empty if HasField() would return true in proto2 or it - is non zero in proto3. A repeated field is non-empty if it contains at least - one element. The fields are ordered by field number. - - Returns: - list[tuple(FieldDescriptor, value)]: field descriptors and values - for all fields in the message which are not empty. The values vary by - field type. - """ - raise NotImplementedError - - def HasField(self, field_name): - """Checks if a certain field is set for the message. - - For a oneof group, checks if any field inside is set. Note that if the - field_name is not defined in the message descriptor, :exc:`ValueError` will - be raised. - - Args: - field_name (str): The name of the field to check for presence. - - Returns: - bool: Whether a value has been set for the named field. - - Raises: - ValueError: if the `field_name` is not a member of this message. - """ - raise NotImplementedError - - def ClearField(self, field_name): - """Clears the contents of a given field. - - Inside a oneof group, clears the field set. If the name neither refers to a - defined field or oneof group, :exc:`ValueError` is raised. - - Args: - field_name (str): The name of the field to check for presence. - - Raises: - ValueError: if the `field_name` is not a member of this message. - """ - raise NotImplementedError - - def WhichOneof(self, oneof_group): - """Returns the name of the field that is set inside a oneof group. - - If no field is set, returns None. - - Args: - oneof_group (str): the name of the oneof group to check. - - Returns: - str or None: The name of the group that is set, or None. - - Raises: - ValueError: no group with the given name exists - """ - raise NotImplementedError - - def HasExtension(self, extension_handle): - """Checks if a certain extension is present for this message. - - Extensions are retrieved using the :attr:`Extensions` mapping (if present). - - Args: - extension_handle: The handle for the extension to check. - - Returns: - bool: Whether the extension is present for this message. - - Raises: - KeyError: if the extension is repeated. Similar to repeated fields, - there is no separate notion of presence: a "not present" repeated - extension is an empty list. - """ - raise NotImplementedError - - def ClearExtension(self, extension_handle): - """Clears the contents of a given extension. - - Args: - extension_handle: The handle for the extension to clear. - """ - raise NotImplementedError - - def UnknownFields(self): - """Returns the UnknownFieldSet. - - Returns: - UnknownFieldSet: The unknown fields stored in this message. - """ - raise NotImplementedError - - def DiscardUnknownFields(self): - """Clears all fields in the :class:`UnknownFieldSet`. - - This operation is recursive for nested message. - """ - raise NotImplementedError - - def ByteSize(self): - """Returns the serialized size of this message. - - Recursively calls ByteSize() on all contained messages. - - Returns: - int: The number of bytes required to serialize this message. - """ - raise NotImplementedError - - @classmethod - def FromString(cls, s): - raise NotImplementedError - - @staticmethod - def RegisterExtension(extension_handle): - raise NotImplementedError - - def _SetListener(self, message_listener): - """Internal method used by the protocol message implementation. - Clients should not call this directly. - - Sets a listener that this message will call on certain state transitions. - - The purpose of this method is to register back-edges from children to - parents at runtime, for the purpose of setting "has" bits and - byte-size-dirty bits in the parent and ancestor objects whenever a child or - descendant object is modified. - - If the client wants to disconnect this Message from the object tree, she - explicitly sets callback to None. - - If message_listener is None, unregisters any existing listener. Otherwise, - message_listener must implement the MessageListener interface in - internal/message_listener.py, and we discard any listener registered - via a previous _SetListener() call. - """ - raise NotImplementedError - - def __getstate__(self): - """Support the pickle protocol.""" - return dict(serialized=self.SerializePartialToString()) - - def __setstate__(self, state): - """Support the pickle protocol.""" - self.__init__() - serialized = state['serialized'] - # On Python 3, using encoding='latin1' is required for unpickling - # protos pickled by Python 2. - if not isinstance(serialized, bytes): - serialized = serialized.encode('latin1') - self.ParseFromString(serialized) - - def __reduce__(self): - message_descriptor = self.DESCRIPTOR - if message_descriptor.containing_type is None: - return type(self), (), self.__getstate__() - # the message type must be nested. - # Python does not pickle nested classes; use the symbol_database on the - # receiving end. - container = message_descriptor - return (_InternalConstructMessage, (container.full_name,), - self.__getstate__()) - - -def _InternalConstructMessage(full_name): - """Constructs a nested message.""" - from google.protobuf import symbol_database # pylint:disable=g-import-not-at-top - - return symbol_database.Default().GetSymbol(full_name)() diff --git a/scripts/protobuf3/protobuf3/message_factory.py b/scripts/protobuf3/protobuf3/message_factory.py deleted file mode 100644 index 3656fa6..0000000 --- a/scripts/protobuf3/protobuf3/message_factory.py +++ /dev/null @@ -1,185 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Provides a factory class for generating dynamic messages. - -The easiest way to use this class is if you have access to the FileDescriptor -protos containing the messages you want to create you can just do the following: - -message_classes = message_factory.GetMessages(iterable_of_file_descriptors) -my_proto_instance = message_classes['some.proto.package.MessageName']() -""" - -__author__ = 'matthewtoia@google.com (Matt Toia)' - -from google.protobuf.internal import api_implementation -from google.protobuf import descriptor_pool -from google.protobuf import message - -if api_implementation.Type() == 'cpp': - from google.protobuf.pyext import cpp_message as message_impl -else: - from google.protobuf.internal import python_message as message_impl - - -# The type of all Message classes. -_GENERATED_PROTOCOL_MESSAGE_TYPE = message_impl.GeneratedProtocolMessageType - - -class MessageFactory(object): - """Factory for creating Proto2 messages from descriptors in a pool.""" - - def __init__(self, pool=None): - """Initializes a new factory.""" - self.pool = pool or descriptor_pool.DescriptorPool() - - # local cache of all classes built from protobuf descriptors - self._classes = {} - - def GetPrototype(self, descriptor): - """Obtains a proto2 message class based on the passed in descriptor. - - Passing a descriptor with a fully qualified name matching a previous - invocation will cause the same class to be returned. - - Args: - descriptor: The descriptor to build from. - - Returns: - A class describing the passed in descriptor. - """ - if descriptor not in self._classes: - result_class = self.CreatePrototype(descriptor) - # The assignment to _classes is redundant for the base implementation, but - # might avoid confusion in cases where CreatePrototype gets overridden and - # does not call the base implementation. - self._classes[descriptor] = result_class - return result_class - return self._classes[descriptor] - - def CreatePrototype(self, descriptor): - """Builds a proto2 message class based on the passed in descriptor. - - Don't call this function directly, it always creates a new class. Call - GetPrototype() instead. This method is meant to be overridden in subblasses - to perform additional operations on the newly constructed class. - - Args: - descriptor: The descriptor to build from. - - Returns: - A class describing the passed in descriptor. - """ - descriptor_name = descriptor.name - result_class = _GENERATED_PROTOCOL_MESSAGE_TYPE( - descriptor_name, - (message.Message,), - { - 'DESCRIPTOR': descriptor, - # If module not set, it wrongly points to message_factory module. - '__module__': None, - }) - result_class._FACTORY = self # pylint: disable=protected-access - # Assign in _classes before doing recursive calls to avoid infinite - # recursion. - self._classes[descriptor] = result_class - for field in descriptor.fields: - if field.message_type: - self.GetPrototype(field.message_type) - for extension in result_class.DESCRIPTOR.extensions: - if extension.containing_type not in self._classes: - self.GetPrototype(extension.containing_type) - extended_class = self._classes[extension.containing_type] - extended_class.RegisterExtension(extension) - return result_class - - def GetMessages(self, files): - """Gets all the messages from a specified file. - - This will find and resolve dependencies, failing if the descriptor - pool cannot satisfy them. - - Args: - files: The file names to extract messages from. - - Returns: - A dictionary mapping proto names to the message classes. This will include - any dependent messages as well as any messages defined in the same file as - a specified message. - """ - result = {} - for file_name in files: - file_desc = self.pool.FindFileByName(file_name) - for desc in file_desc.message_types_by_name.values(): - result[desc.full_name] = self.GetPrototype(desc) - - # While the extension FieldDescriptors are created by the descriptor pool, - # the python classes created in the factory need them to be registered - # explicitly, which is done below. - # - # The call to RegisterExtension will specifically check if the - # extension was already registered on the object and either - # ignore the registration if the original was the same, or raise - # an error if they were different. - - for extension in file_desc.extensions_by_name.values(): - if extension.containing_type not in self._classes: - self.GetPrototype(extension.containing_type) - extended_class = self._classes[extension.containing_type] - extended_class.RegisterExtension(extension) - return result - - -_FACTORY = MessageFactory() - - -def GetMessages(file_protos): - """Builds a dictionary of all the messages available in a set of files. - - Args: - file_protos: Iterable of FileDescriptorProto to build messages out of. - - Returns: - A dictionary mapping proto names to the message classes. This will include - any dependent messages as well as any messages defined in the same file as - a specified message. - """ - # The cpp implementation of the protocol buffer library requires to add the - # message in topological order of the dependency graph. - file_by_name = {file_proto.name: file_proto for file_proto in file_protos} - def _AddFile(file_proto): - for dependency in file_proto.dependency: - if dependency in file_by_name: - # Remove from elements to be visited, in order to cut cycles. - _AddFile(file_by_name.pop(dependency)) - _FACTORY.pool.Add(file_proto) - while file_by_name: - _AddFile(file_by_name.popitem()[1]) - return _FACTORY.GetMessages([file_proto.name for file_proto in file_protos]) diff --git a/scripts/protobuf3/protobuf3/proto_builder.py b/scripts/protobuf3/protobuf3/proto_builder.py deleted file mode 100644 index a4667ce..0000000 --- a/scripts/protobuf3/protobuf3/proto_builder.py +++ /dev/null @@ -1,134 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Dynamic Protobuf class creator.""" - -from collections import OrderedDict -import hashlib -import os - -from google.protobuf import descriptor_pb2 -from google.protobuf import descriptor -from google.protobuf import message_factory - - -def _GetMessageFromFactory(factory, full_name): - """Get a proto class from the MessageFactory by name. - - Args: - factory: a MessageFactory instance. - full_name: str, the fully qualified name of the proto type. - Returns: - A class, for the type identified by full_name. - Raises: - KeyError, if the proto is not found in the factory's descriptor pool. - """ - proto_descriptor = factory.pool.FindMessageTypeByName(full_name) - proto_cls = factory.GetPrototype(proto_descriptor) - return proto_cls - - -def MakeSimpleProtoClass(fields, full_name=None, pool=None): - """Create a Protobuf class whose fields are basic types. - - Note: this doesn't validate field names! - - Args: - fields: dict of {name: field_type} mappings for each field in the proto. If - this is an OrderedDict the order will be maintained, otherwise the - fields will be sorted by name. - full_name: optional str, the fully-qualified name of the proto type. - pool: optional DescriptorPool instance. - Returns: - a class, the new protobuf class with a FileDescriptor. - """ - factory = message_factory.MessageFactory(pool=pool) - - if full_name is not None: - try: - proto_cls = _GetMessageFromFactory(factory, full_name) - return proto_cls - except KeyError: - # The factory's DescriptorPool doesn't know about this class yet. - pass - - # Get a list of (name, field_type) tuples from the fields dict. If fields was - # an OrderedDict we keep the order, but otherwise we sort the field to ensure - # consistent ordering. - field_items = fields.items() - if not isinstance(fields, OrderedDict): - field_items = sorted(field_items) - - # Use a consistent file name that is unlikely to conflict with any imported - # proto files. - fields_hash = hashlib.sha1() - for f_name, f_type in field_items: - fields_hash.update(f_name.encode('utf-8')) - fields_hash.update(str(f_type).encode('utf-8')) - proto_file_name = fields_hash.hexdigest() + '.proto' - - # If the proto is anonymous, use the same hash to name it. - if full_name is None: - full_name = ('net.proto2.python.public.proto_builder.AnonymousProto_' + - fields_hash.hexdigest()) - try: - proto_cls = _GetMessageFromFactory(factory, full_name) - return proto_cls - except KeyError: - # The factory's DescriptorPool doesn't know about this class yet. - pass - - # This is the first time we see this proto: add a new descriptor to the pool. - factory.pool.Add( - _MakeFileDescriptorProto(proto_file_name, full_name, field_items)) - return _GetMessageFromFactory(factory, full_name) - - -def _MakeFileDescriptorProto(proto_file_name, full_name, field_items): - """Populate FileDescriptorProto for MessageFactory's DescriptorPool.""" - package, name = full_name.rsplit('.', 1) - file_proto = descriptor_pb2.FileDescriptorProto() - file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name) - file_proto.package = package - desc_proto = file_proto.message_type.add() - desc_proto.name = name - for f_number, (f_name, f_type) in enumerate(field_items, 1): - field_proto = desc_proto.field.add() - field_proto.name = f_name - # # If the number falls in the reserved range, reassign it to the correct - # # number after the range. - if f_number >= descriptor.FieldDescriptor.FIRST_RESERVED_FIELD_NUMBER: - f_number += ( - descriptor.FieldDescriptor.LAST_RESERVED_FIELD_NUMBER - - descriptor.FieldDescriptor.FIRST_RESERVED_FIELD_NUMBER + 1) - field_proto.number = f_number - field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL - field_proto.type = f_type - return file_proto diff --git a/scripts/protobuf3/protobuf3/pyext/__init__.py b/scripts/protobuf3/protobuf3/pyext/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/protobuf3/protobuf3/pyext/cpp_message.py b/scripts/protobuf3/protobuf3/pyext/cpp_message.py deleted file mode 100644 index fc8eb32..0000000 --- a/scripts/protobuf3/protobuf3/pyext/cpp_message.py +++ /dev/null @@ -1,65 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Protocol message implementation hooks for C++ implementation. - -Contains helper functions used to create protocol message classes from -Descriptor objects at runtime backed by the protocol buffer C++ API. -""" - -__author__ = 'tibell@google.com (Johan Tibell)' - -from google.protobuf.pyext import _message - - -class GeneratedProtocolMessageType(_message.MessageMeta): - - """Metaclass for protocol message classes created at runtime from Descriptors. - - The protocol compiler currently uses this metaclass to create protocol - message classes at runtime. Clients can also manually create their own - classes at runtime, as in this example: - - mydescriptor = Descriptor(.....) - factory = symbol_database.Default() - factory.pool.AddDescriptor(mydescriptor) - MyProtoClass = factory.GetPrototype(mydescriptor) - myproto_instance = MyProtoClass() - myproto.foo_field = 23 - ... - - The above example will not work for nested types. If you wish to include them, - use reflection.MakeClass() instead of manually instantiating the class in - order to create the appropriate class structure. - """ - - # Must be consistent with the protocol-compiler code in - # proto2/compiler/internal/generator.*. - _DESCRIPTOR_KEY = 'DESCRIPTOR' diff --git a/scripts/protobuf3/protobuf3/pyext/python_pb2.py b/scripts/protobuf3/protobuf3/pyext/python_pb2.py deleted file mode 100644 index 2c6ecf4..0000000 --- a/scripts/protobuf3/protobuf3/pyext/python_pb2.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/pyext/python.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"google/protobuf/pyext/python.proto\x12\x1fgoogle.protobuf.python.internal\"\xbc\x02\n\x0cTestAllTypes\x12\\\n\x17repeated_nested_message\x18\x01 \x03(\x0b\x32;.google.protobuf.python.internal.TestAllTypes.NestedMessage\x12\\\n\x17optional_nested_message\x18\x02 \x01(\x0b\x32;.google.protobuf.python.internal.TestAllTypes.NestedMessage\x12\x16\n\x0eoptional_int32\x18\x03 \x01(\x05\x1aX\n\rNestedMessage\x12\n\n\x02\x62\x62\x18\x01 \x01(\x05\x12;\n\x02\x63\x63\x18\x02 \x01(\x0b\x32/.google.protobuf.python.internal.ForeignMessage\"&\n\x0e\x46oreignMessage\x12\t\n\x01\x63\x18\x01 \x01(\x05\x12\t\n\x01\x64\x18\x02 \x03(\x05\"\x1d\n\x11TestAllExtensions*\x08\x08\x01\x10\x80\x80\x80\x80\x02:\x9a\x01\n!optional_nested_message_extension\x12\x32.google.protobuf.python.internal.TestAllExtensions\x18\x01 \x01(\x0b\x32;.google.protobuf.python.internal.TestAllTypes.NestedMessage:\x9a\x01\n!repeated_nested_message_extension\x12\x32.google.protobuf.python.internal.TestAllExtensions\x18\x02 \x03(\x0b\x32;.google.protobuf.python.internal.TestAllTypes.NestedMessageB\x02H\x01') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.pyext.python_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - TestAllExtensions.RegisterExtension(optional_nested_message_extension) - TestAllExtensions.RegisterExtension(repeated_nested_message_extension) - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'H\001' - _TESTALLTYPES._serialized_start=72 - _TESTALLTYPES._serialized_end=388 - _TESTALLTYPES_NESTEDMESSAGE._serialized_start=300 - _TESTALLTYPES_NESTEDMESSAGE._serialized_end=388 - _FOREIGNMESSAGE._serialized_start=390 - _FOREIGNMESSAGE._serialized_end=428 - _TESTALLEXTENSIONS._serialized_start=430 - _TESTALLEXTENSIONS._serialized_end=459 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/reflection.py b/scripts/protobuf3/protobuf3/reflection.py deleted file mode 100644 index 81e1885..0000000 --- a/scripts/protobuf3/protobuf3/reflection.py +++ /dev/null @@ -1,95 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# This code is meant to work on Python 2.4 and above only. - -"""Contains a metaclass and helper functions used to create -protocol message classes from Descriptor objects at runtime. - -Recall that a metaclass is the "type" of a class. -(A class is to a metaclass what an instance is to a class.) - -In this case, we use the GeneratedProtocolMessageType metaclass -to inject all the useful functionality into the classes -output by the protocol compiler at compile-time. - -The upshot of all this is that the real implementation -details for ALL pure-Python protocol buffers are *here in -this file*. -""" - -__author__ = 'robinson@google.com (Will Robinson)' - - -from google.protobuf import message_factory -from google.protobuf import symbol_database - -# The type of all Message classes. -# Part of the public interface, but normally only used by message factories. -GeneratedProtocolMessageType = message_factory._GENERATED_PROTOCOL_MESSAGE_TYPE - -MESSAGE_CLASS_CACHE = {} - - -# Deprecated. Please NEVER use reflection.ParseMessage(). -def ParseMessage(descriptor, byte_str): - """Generate a new Message instance from this Descriptor and a byte string. - - DEPRECATED: ParseMessage is deprecated because it is using MakeClass(). - Please use MessageFactory.GetPrototype() instead. - - Args: - descriptor: Protobuf Descriptor object - byte_str: Serialized protocol buffer byte string - - Returns: - Newly created protobuf Message object. - """ - result_class = MakeClass(descriptor) - new_msg = result_class() - new_msg.ParseFromString(byte_str) - return new_msg - - -# Deprecated. Please NEVER use reflection.MakeClass(). -def MakeClass(descriptor): - """Construct a class object for a protobuf described by descriptor. - - DEPRECATED: use MessageFactory.GetPrototype() instead. - - Args: - descriptor: A descriptor.Descriptor object describing the protobuf. - Returns: - The Message class object described by the descriptor. - """ - # Original implementation leads to duplicate message classes, which won't play - # well with extensions. Message factory info is also missing. - # Redirect to message_factory. - return symbol_database.Default().GetPrototype(descriptor) diff --git a/scripts/protobuf3/protobuf3/service.py b/scripts/protobuf3/protobuf3/service.py deleted file mode 100644 index 5625246..0000000 --- a/scripts/protobuf3/protobuf3/service.py +++ /dev/null @@ -1,228 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""DEPRECATED: Declares the RPC service interfaces. - -This module declares the abstract interfaces underlying proto2 RPC -services. These are intended to be independent of any particular RPC -implementation, so that proto2 services can be used on top of a variety -of implementations. Starting with version 2.3.0, RPC implementations should -not try to build on these, but should instead provide code generator plugins -which generate code specific to the particular RPC implementation. This way -the generated code can be more appropriate for the implementation in use -and can avoid unnecessary layers of indirection. -""" - -__author__ = 'petar@google.com (Petar Petrov)' - - -class RpcException(Exception): - """Exception raised on failed blocking RPC method call.""" - pass - - -class Service(object): - - """Abstract base interface for protocol-buffer-based RPC services. - - Services themselves are abstract classes (implemented either by servers or as - stubs), but they subclass this base interface. The methods of this - interface can be used to call the methods of the service without knowing - its exact type at compile time (analogous to the Message interface). - """ - - def GetDescriptor(): - """Retrieves this service's descriptor.""" - raise NotImplementedError - - def CallMethod(self, method_descriptor, rpc_controller, - request, done): - """Calls a method of the service specified by method_descriptor. - - If "done" is None then the call is blocking and the response - message will be returned directly. Otherwise the call is asynchronous - and "done" will later be called with the response value. - - In the blocking case, RpcException will be raised on error. - - Preconditions: - - * method_descriptor.service == GetDescriptor - * request is of the exact same classes as returned by - GetRequestClass(method). - * After the call has started, the request must not be modified. - * "rpc_controller" is of the correct type for the RPC implementation being - used by this Service. For stubs, the "correct type" depends on the - RpcChannel which the stub is using. - - Postconditions: - - * "done" will be called when the method is complete. This may be - before CallMethod() returns or it may be at some point in the future. - * If the RPC failed, the response value passed to "done" will be None. - Further details about the failure can be found by querying the - RpcController. - """ - raise NotImplementedError - - def GetRequestClass(self, method_descriptor): - """Returns the class of the request message for the specified method. - - CallMethod() requires that the request is of a particular subclass of - Message. GetRequestClass() gets the default instance of this required - type. - - Example: - method = service.GetDescriptor().FindMethodByName("Foo") - request = stub.GetRequestClass(method)() - request.ParseFromString(input) - service.CallMethod(method, request, callback) - """ - raise NotImplementedError - - def GetResponseClass(self, method_descriptor): - """Returns the class of the response message for the specified method. - - This method isn't really needed, as the RpcChannel's CallMethod constructs - the response protocol message. It's provided anyway in case it is useful - for the caller to know the response type in advance. - """ - raise NotImplementedError - - -class RpcController(object): - - """An RpcController mediates a single method call. - - The primary purpose of the controller is to provide a way to manipulate - settings specific to the RPC implementation and to find out about RPC-level - errors. The methods provided by the RpcController interface are intended - to be a "least common denominator" set of features which we expect all - implementations to support. Specific implementations may provide more - advanced features (e.g. deadline propagation). - """ - - # Client-side methods below - - def Reset(self): - """Resets the RpcController to its initial state. - - After the RpcController has been reset, it may be reused in - a new call. Must not be called while an RPC is in progress. - """ - raise NotImplementedError - - def Failed(self): - """Returns true if the call failed. - - After a call has finished, returns true if the call failed. The possible - reasons for failure depend on the RPC implementation. Failed() must not - be called before a call has finished. If Failed() returns true, the - contents of the response message are undefined. - """ - raise NotImplementedError - - def ErrorText(self): - """If Failed is true, returns a human-readable description of the error.""" - raise NotImplementedError - - def StartCancel(self): - """Initiate cancellation. - - Advises the RPC system that the caller desires that the RPC call be - canceled. The RPC system may cancel it immediately, may wait awhile and - then cancel it, or may not even cancel the call at all. If the call is - canceled, the "done" callback will still be called and the RpcController - will indicate that the call failed at that time. - """ - raise NotImplementedError - - # Server-side methods below - - def SetFailed(self, reason): - """Sets a failure reason. - - Causes Failed() to return true on the client side. "reason" will be - incorporated into the message returned by ErrorText(). If you find - you need to return machine-readable information about failures, you - should incorporate it into your response protocol buffer and should - NOT call SetFailed(). - """ - raise NotImplementedError - - def IsCanceled(self): - """Checks if the client cancelled the RPC. - - If true, indicates that the client canceled the RPC, so the server may - as well give up on replying to it. The server should still call the - final "done" callback. - """ - raise NotImplementedError - - def NotifyOnCancel(self, callback): - """Sets a callback to invoke on cancel. - - Asks that the given callback be called when the RPC is canceled. The - callback will always be called exactly once. If the RPC completes without - being canceled, the callback will be called after completion. If the RPC - has already been canceled when NotifyOnCancel() is called, the callback - will be called immediately. - - NotifyOnCancel() must be called no more than once per request. - """ - raise NotImplementedError - - -class RpcChannel(object): - - """Abstract interface for an RPC channel. - - An RpcChannel represents a communication line to a service which can be used - to call that service's methods. The service may be running on another - machine. Normally, you should not use an RpcChannel directly, but instead - construct a stub {@link Service} wrapping it. Example: - - Example: - RpcChannel channel = rpcImpl.Channel("remotehost.example.com:1234") - RpcController controller = rpcImpl.Controller() - MyService service = MyService_Stub(channel) - service.MyMethod(controller, request, callback) - """ - - def CallMethod(self, method_descriptor, rpc_controller, - request, response_class, done): - """Calls the method identified by the descriptor. - - Call the given method of the remote service. The signature of this - procedure looks the same as Service.CallMethod(), but the requirements - are less strict in one important way: the request object doesn't have to - be of any specific class as long as its descriptor is method.input_type. - """ - raise NotImplementedError diff --git a/scripts/protobuf3/protobuf3/service_reflection.py b/scripts/protobuf3/protobuf3/service_reflection.py deleted file mode 100644 index f82ab71..0000000 --- a/scripts/protobuf3/protobuf3/service_reflection.py +++ /dev/null @@ -1,295 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Contains metaclasses used to create protocol service and service stub -classes from ServiceDescriptor objects at runtime. - -The GeneratedServiceType and GeneratedServiceStubType metaclasses are used to -inject all useful functionality into the classes output by the protocol -compiler at compile-time. -""" - -__author__ = 'petar@google.com (Petar Petrov)' - - -class GeneratedServiceType(type): - - """Metaclass for service classes created at runtime from ServiceDescriptors. - - Implementations for all methods described in the Service class are added here - by this class. We also create properties to allow getting/setting all fields - in the protocol message. - - The protocol compiler currently uses this metaclass to create protocol service - classes at runtime. Clients can also manually create their own classes at - runtime, as in this example:: - - mydescriptor = ServiceDescriptor(.....) - class MyProtoService(service.Service): - __metaclass__ = GeneratedServiceType - DESCRIPTOR = mydescriptor - myservice_instance = MyProtoService() - # ... - """ - - _DESCRIPTOR_KEY = 'DESCRIPTOR' - - def __init__(cls, name, bases, dictionary): - """Creates a message service class. - - Args: - name: Name of the class (ignored, but required by the metaclass - protocol). - bases: Base classes of the class being constructed. - dictionary: The class dictionary of the class being constructed. - dictionary[_DESCRIPTOR_KEY] must contain a ServiceDescriptor object - describing this protocol service type. - """ - # Don't do anything if this class doesn't have a descriptor. This happens - # when a service class is subclassed. - if GeneratedServiceType._DESCRIPTOR_KEY not in dictionary: - return - - descriptor = dictionary[GeneratedServiceType._DESCRIPTOR_KEY] - service_builder = _ServiceBuilder(descriptor) - service_builder.BuildService(cls) - cls.DESCRIPTOR = descriptor - - -class GeneratedServiceStubType(GeneratedServiceType): - - """Metaclass for service stubs created at runtime from ServiceDescriptors. - - This class has similar responsibilities as GeneratedServiceType, except that - it creates the service stub classes. - """ - - _DESCRIPTOR_KEY = 'DESCRIPTOR' - - def __init__(cls, name, bases, dictionary): - """Creates a message service stub class. - - Args: - name: Name of the class (ignored, here). - bases: Base classes of the class being constructed. - dictionary: The class dictionary of the class being constructed. - dictionary[_DESCRIPTOR_KEY] must contain a ServiceDescriptor object - describing this protocol service type. - """ - super(GeneratedServiceStubType, cls).__init__(name, bases, dictionary) - # Don't do anything if this class doesn't have a descriptor. This happens - # when a service stub is subclassed. - if GeneratedServiceStubType._DESCRIPTOR_KEY not in dictionary: - return - - descriptor = dictionary[GeneratedServiceStubType._DESCRIPTOR_KEY] - service_stub_builder = _ServiceStubBuilder(descriptor) - service_stub_builder.BuildServiceStub(cls) - - -class _ServiceBuilder(object): - - """This class constructs a protocol service class using a service descriptor. - - Given a service descriptor, this class constructs a class that represents - the specified service descriptor. One service builder instance constructs - exactly one service class. That means all instances of that class share the - same builder. - """ - - def __init__(self, service_descriptor): - """Initializes an instance of the service class builder. - - Args: - service_descriptor: ServiceDescriptor to use when constructing the - service class. - """ - self.descriptor = service_descriptor - - def BuildService(builder, cls): - """Constructs the service class. - - Args: - cls: The class that will be constructed. - """ - - # CallMethod needs to operate with an instance of the Service class. This - # internal wrapper function exists only to be able to pass the service - # instance to the method that does the real CallMethod work. - # Making sure to use exact argument names from the abstract interface in - # service.py to match the type signature - def _WrapCallMethod(self, method_descriptor, rpc_controller, request, done): - return builder._CallMethod(self, method_descriptor, rpc_controller, - request, done) - - def _WrapGetRequestClass(self, method_descriptor): - return builder._GetRequestClass(method_descriptor) - - def _WrapGetResponseClass(self, method_descriptor): - return builder._GetResponseClass(method_descriptor) - - builder.cls = cls - cls.CallMethod = _WrapCallMethod - cls.GetDescriptor = staticmethod(lambda: builder.descriptor) - cls.GetDescriptor.__doc__ = 'Returns the service descriptor.' - cls.GetRequestClass = _WrapGetRequestClass - cls.GetResponseClass = _WrapGetResponseClass - for method in builder.descriptor.methods: - setattr(cls, method.name, builder._GenerateNonImplementedMethod(method)) - - def _CallMethod(self, srvc, method_descriptor, - rpc_controller, request, callback): - """Calls the method described by a given method descriptor. - - Args: - srvc: Instance of the service for which this method is called. - method_descriptor: Descriptor that represent the method to call. - rpc_controller: RPC controller to use for this method's execution. - request: Request protocol message. - callback: A callback to invoke after the method has completed. - """ - if method_descriptor.containing_service != self.descriptor: - raise RuntimeError( - 'CallMethod() given method descriptor for wrong service type.') - method = getattr(srvc, method_descriptor.name) - return method(rpc_controller, request, callback) - - def _GetRequestClass(self, method_descriptor): - """Returns the class of the request protocol message. - - Args: - method_descriptor: Descriptor of the method for which to return the - request protocol message class. - - Returns: - A class that represents the input protocol message of the specified - method. - """ - if method_descriptor.containing_service != self.descriptor: - raise RuntimeError( - 'GetRequestClass() given method descriptor for wrong service type.') - return method_descriptor.input_type._concrete_class - - def _GetResponseClass(self, method_descriptor): - """Returns the class of the response protocol message. - - Args: - method_descriptor: Descriptor of the method for which to return the - response protocol message class. - - Returns: - A class that represents the output protocol message of the specified - method. - """ - if method_descriptor.containing_service != self.descriptor: - raise RuntimeError( - 'GetResponseClass() given method descriptor for wrong service type.') - return method_descriptor.output_type._concrete_class - - def _GenerateNonImplementedMethod(self, method): - """Generates and returns a method that can be set for a service methods. - - Args: - method: Descriptor of the service method for which a method is to be - generated. - - Returns: - A method that can be added to the service class. - """ - return lambda inst, rpc_controller, request, callback: ( - self._NonImplementedMethod(method.name, rpc_controller, callback)) - - def _NonImplementedMethod(self, method_name, rpc_controller, callback): - """The body of all methods in the generated service class. - - Args: - method_name: Name of the method being executed. - rpc_controller: RPC controller used to execute this method. - callback: A callback which will be invoked when the method finishes. - """ - rpc_controller.SetFailed('Method %s not implemented.' % method_name) - callback(None) - - -class _ServiceStubBuilder(object): - - """Constructs a protocol service stub class using a service descriptor. - - Given a service descriptor, this class constructs a suitable stub class. - A stub is just a type-safe wrapper around an RpcChannel which emulates a - local implementation of the service. - - One service stub builder instance constructs exactly one class. It means all - instances of that class share the same service stub builder. - """ - - def __init__(self, service_descriptor): - """Initializes an instance of the service stub class builder. - - Args: - service_descriptor: ServiceDescriptor to use when constructing the - stub class. - """ - self.descriptor = service_descriptor - - def BuildServiceStub(self, cls): - """Constructs the stub class. - - Args: - cls: The class that will be constructed. - """ - - def _ServiceStubInit(stub, rpc_channel): - stub.rpc_channel = rpc_channel - self.cls = cls - cls.__init__ = _ServiceStubInit - for method in self.descriptor.methods: - setattr(cls, method.name, self._GenerateStubMethod(method)) - - def _GenerateStubMethod(self, method): - return (lambda inst, rpc_controller, request, callback=None: - self._StubMethod(inst, method, rpc_controller, request, callback)) - - def _StubMethod(self, stub, method_descriptor, - rpc_controller, request, callback): - """The body of all service methods in the generated stub class. - - Args: - stub: Stub instance. - method_descriptor: Descriptor of the invoked method. - rpc_controller: Rpc controller to execute the method. - request: Request protocol message. - callback: A callback to execute when the method finishes. - Returns: - Response message (in case of blocking call). - """ - return stub.rpc_channel.CallMethod( - method_descriptor, rpc_controller, request, - method_descriptor.output_type._concrete_class, callback) diff --git a/scripts/protobuf3/protobuf3/source_context_pb2.py b/scripts/protobuf3/protobuf3/source_context_pb2.py deleted file mode 100644 index 30cca2e..0000000 --- a/scripts/protobuf3/protobuf3/source_context_pb2.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/source_context.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$google/protobuf/source_context.proto\x12\x0fgoogle.protobuf\"\"\n\rSourceContext\x12\x11\n\tfile_name\x18\x01 \x01(\tB\x8a\x01\n\x13\x63om.google.protobufB\x12SourceContextProtoP\x01Z6google.golang.org/protobuf/types/known/sourcecontextpb\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.source_context_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\022SourceContextProtoP\001Z6google.golang.org/protobuf/types/known/sourcecontextpb\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' - _SOURCECONTEXT._serialized_start=57 - _SOURCECONTEXT._serialized_end=91 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/struct_pb2.py b/scripts/protobuf3/protobuf3/struct_pb2.py deleted file mode 100644 index 149728c..0000000 --- a/scripts/protobuf3/protobuf3/struct_pb2.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/struct.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1cgoogle/protobuf/struct.proto\x12\x0fgoogle.protobuf\"\x84\x01\n\x06Struct\x12\x33\n\x06\x66ields\x18\x01 \x03(\x0b\x32#.google.protobuf.Struct.FieldsEntry\x1a\x45\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12%\n\x05value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.Value:\x02\x38\x01\"\xea\x01\n\x05Value\x12\x30\n\nnull_value\x18\x01 \x01(\x0e\x32\x1a.google.protobuf.NullValueH\x00\x12\x16\n\x0cnumber_value\x18\x02 \x01(\x01H\x00\x12\x16\n\x0cstring_value\x18\x03 \x01(\tH\x00\x12\x14\n\nbool_value\x18\x04 \x01(\x08H\x00\x12/\n\x0cstruct_value\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x12\x30\n\nlist_value\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.ListValueH\x00\x42\x06\n\x04kind\"3\n\tListValue\x12&\n\x06values\x18\x01 \x03(\x0b\x32\x16.google.protobuf.Value*\x1b\n\tNullValue\x12\x0e\n\nNULL_VALUE\x10\x00\x42\x7f\n\x13\x63om.google.protobufB\x0bStructProtoP\x01Z/google.golang.org/protobuf/types/known/structpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.struct_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\013StructProtoP\001Z/google.golang.org/protobuf/types/known/structpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' - _STRUCT_FIELDSENTRY._options = None - _STRUCT_FIELDSENTRY._serialized_options = b'8\001' - _NULLVALUE._serialized_start=474 - _NULLVALUE._serialized_end=501 - _STRUCT._serialized_start=50 - _STRUCT._serialized_end=182 - _STRUCT_FIELDSENTRY._serialized_start=113 - _STRUCT_FIELDSENTRY._serialized_end=182 - _VALUE._serialized_start=185 - _VALUE._serialized_end=419 - _LISTVALUE._serialized_start=421 - _LISTVALUE._serialized_end=472 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/symbol_database.py b/scripts/protobuf3/protobuf3/symbol_database.py deleted file mode 100644 index fdcf8cf..0000000 --- a/scripts/protobuf3/protobuf3/symbol_database.py +++ /dev/null @@ -1,194 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""A database of Python protocol buffer generated symbols. - -SymbolDatabase is the MessageFactory for messages generated at compile time, -and makes it easy to create new instances of a registered type, given only the -type's protocol buffer symbol name. - -Example usage:: - - db = symbol_database.SymbolDatabase() - - # Register symbols of interest, from one or multiple files. - db.RegisterFileDescriptor(my_proto_pb2.DESCRIPTOR) - db.RegisterMessage(my_proto_pb2.MyMessage) - db.RegisterEnumDescriptor(my_proto_pb2.MyEnum.DESCRIPTOR) - - # The database can be used as a MessageFactory, to generate types based on - # their name: - types = db.GetMessages(['my_proto.proto']) - my_message_instance = types['MyMessage']() - - # The database's underlying descriptor pool can be queried, so it's not - # necessary to know a type's filename to be able to generate it: - filename = db.pool.FindFileContainingSymbol('MyMessage') - my_message_instance = db.GetMessages([filename])['MyMessage']() - - # This functionality is also provided directly via a convenience method: - my_message_instance = db.GetSymbol('MyMessage')() -""" - - -from google.protobuf.internal import api_implementation -from google.protobuf import descriptor_pool -from google.protobuf import message_factory - - -class SymbolDatabase(message_factory.MessageFactory): - """A database of Python generated symbols.""" - - def RegisterMessage(self, message): - """Registers the given message type in the local database. - - Calls to GetSymbol() and GetMessages() will return messages registered here. - - Args: - message: A :class:`google.protobuf.message.Message` subclass (or - instance); its descriptor will be registered. - - Returns: - The provided message. - """ - - desc = message.DESCRIPTOR - self._classes[desc] = message - self.RegisterMessageDescriptor(desc) - return message - - def RegisterMessageDescriptor(self, message_descriptor): - """Registers the given message descriptor in the local database. - - Args: - message_descriptor (Descriptor): the message descriptor to add. - """ - if api_implementation.Type() == 'python': - # pylint: disable=protected-access - self.pool._AddDescriptor(message_descriptor) - - def RegisterEnumDescriptor(self, enum_descriptor): - """Registers the given enum descriptor in the local database. - - Args: - enum_descriptor (EnumDescriptor): The enum descriptor to register. - - Returns: - EnumDescriptor: The provided descriptor. - """ - if api_implementation.Type() == 'python': - # pylint: disable=protected-access - self.pool._AddEnumDescriptor(enum_descriptor) - return enum_descriptor - - def RegisterServiceDescriptor(self, service_descriptor): - """Registers the given service descriptor in the local database. - - Args: - service_descriptor (ServiceDescriptor): the service descriptor to - register. - """ - if api_implementation.Type() == 'python': - # pylint: disable=protected-access - self.pool._AddServiceDescriptor(service_descriptor) - - def RegisterFileDescriptor(self, file_descriptor): - """Registers the given file descriptor in the local database. - - Args: - file_descriptor (FileDescriptor): The file descriptor to register. - """ - if api_implementation.Type() == 'python': - # pylint: disable=protected-access - self.pool._InternalAddFileDescriptor(file_descriptor) - - def GetSymbol(self, symbol): - """Tries to find a symbol in the local database. - - Currently, this method only returns message.Message instances, however, if - may be extended in future to support other symbol types. - - Args: - symbol (str): a protocol buffer symbol. - - Returns: - A Python class corresponding to the symbol. - - Raises: - KeyError: if the symbol could not be found. - """ - - return self._classes[self.pool.FindMessageTypeByName(symbol)] - - def GetMessages(self, files): - # TODO(amauryfa): Fix the differences with MessageFactory. - """Gets all registered messages from a specified file. - - Only messages already created and registered will be returned; (this is the - case for imported _pb2 modules) - But unlike MessageFactory, this version also returns already defined nested - messages, but does not register any message extensions. - - Args: - files (list[str]): The file names to extract messages from. - - Returns: - A dictionary mapping proto names to the message classes. - - Raises: - KeyError: if a file could not be found. - """ - - def _GetAllMessages(desc): - """Walk a message Descriptor and recursively yields all message names.""" - yield desc - for msg_desc in desc.nested_types: - for nested_desc in _GetAllMessages(msg_desc): - yield nested_desc - - result = {} - for file_name in files: - file_desc = self.pool.FindFileByName(file_name) - for msg_desc in file_desc.message_types_by_name.values(): - for desc in _GetAllMessages(msg_desc): - try: - result[desc.full_name] = self._classes[desc] - except KeyError: - # This descriptor has no registered class, skip it. - pass - return result - - -_DEFAULT = SymbolDatabase(pool=descriptor_pool.Default()) - - -def Default(): - """Returns the default SymbolDatabase.""" - return _DEFAULT diff --git a/scripts/protobuf3/protobuf3/text_encoding.py b/scripts/protobuf3/protobuf3/text_encoding.py deleted file mode 100644 index 759cf11..0000000 --- a/scripts/protobuf3/protobuf3/text_encoding.py +++ /dev/null @@ -1,110 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Encoding related utilities.""" -import re - -_cescape_chr_to_symbol_map = {} -_cescape_chr_to_symbol_map[9] = r'\t' # optional escape -_cescape_chr_to_symbol_map[10] = r'\n' # optional escape -_cescape_chr_to_symbol_map[13] = r'\r' # optional escape -_cescape_chr_to_symbol_map[34] = r'\"' # necessary escape -_cescape_chr_to_symbol_map[39] = r"\'" # optional escape -_cescape_chr_to_symbol_map[92] = r'\\' # necessary escape - -# Lookup table for unicode -_cescape_unicode_to_str = [chr(i) for i in range(0, 256)] -for byte, string in _cescape_chr_to_symbol_map.items(): - _cescape_unicode_to_str[byte] = string - -# Lookup table for non-utf8, with necessary escapes at (o >= 127 or o < 32) -_cescape_byte_to_str = ([r'\%03o' % i for i in range(0, 32)] + - [chr(i) for i in range(32, 127)] + - [r'\%03o' % i for i in range(127, 256)]) -for byte, string in _cescape_chr_to_symbol_map.items(): - _cescape_byte_to_str[byte] = string -del byte, string - - -def CEscape(text, as_utf8): - # type: (...) -> str - """Escape a bytes string for use in an text protocol buffer. - - Args: - text: A byte string to be escaped. - as_utf8: Specifies if result may contain non-ASCII characters. - In Python 3 this allows unescaped non-ASCII Unicode characters. - In Python 2 the return value will be valid UTF-8 rather than only ASCII. - Returns: - Escaped string (str). - """ - # Python's text.encode() 'string_escape' or 'unicode_escape' codecs do not - # satisfy our needs; they encodes unprintable characters using two-digit hex - # escapes whereas our C++ unescaping function allows hex escapes to be any - # length. So, "\0011".encode('string_escape') ends up being "\\x011", which - # will be decoded in C++ as a single-character string with char code 0x11. - text_is_unicode = isinstance(text, str) - if as_utf8 and text_is_unicode: - # We're already unicode, no processing beyond control char escapes. - return text.translate(_cescape_chr_to_symbol_map) - ord_ = ord if text_is_unicode else lambda x: x # bytes iterate as ints. - if as_utf8: - return ''.join(_cescape_unicode_to_str[ord_(c)] for c in text) - return ''.join(_cescape_byte_to_str[ord_(c)] for c in text) - - -_CUNESCAPE_HEX = re.compile(r'(\\+)x([0-9a-fA-F])(?![0-9a-fA-F])') - - -def CUnescape(text): - # type: (str) -> bytes - """Unescape a text string with C-style escape sequences to UTF-8 bytes. - - Args: - text: The data to parse in a str. - Returns: - A byte string. - """ - - def ReplaceHex(m): - # Only replace the match if the number of leading back slashes is odd. i.e. - # the slash itself is not escaped. - if len(m.group(1)) & 1: - return m.group(1) + 'x0' + m.group(2) - return m.group(0) - - # This is required because the 'string_escape' encoding doesn't - # allow single-digit hex escapes (like '\xf'). - result = _CUNESCAPE_HEX.sub(ReplaceHex, text) - - return (result.encode('utf-8') # Make it bytes to allow decode. - .decode('unicode_escape') - # Make it bytes again to return the proper type. - .encode('raw_unicode_escape')) diff --git a/scripts/protobuf3/protobuf3/text_format.py b/scripts/protobuf3/protobuf3/text_format.py deleted file mode 100644 index 412385c..0000000 --- a/scripts/protobuf3/protobuf3/text_format.py +++ /dev/null @@ -1,1795 +0,0 @@ -# Protocol Buffers - Google's data interchange format -# Copyright 2008 Google Inc. All rights reserved. -# https://developers.google.com/protocol-buffers/ -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Contains routines for printing protocol messages in text format. - -Simple usage example:: - - # Create a proto object and serialize it to a text proto string. - message = my_proto_pb2.MyMessage(foo='bar') - text_proto = text_format.MessageToString(message) - - # Parse a text proto string. - message = text_format.Parse(text_proto, my_proto_pb2.MyMessage()) -""" - -__author__ = 'kenton@google.com (Kenton Varda)' - -# TODO(b/129989314) Import thread contention leads to test failures. -import encodings.raw_unicode_escape # pylint: disable=unused-import -import encodings.unicode_escape # pylint: disable=unused-import -import io -import math -import re - -from google.protobuf.internal import decoder -from google.protobuf.internal import type_checkers -from google.protobuf import descriptor -from google.protobuf import text_encoding - -# pylint: disable=g-import-not-at-top -__all__ = ['MessageToString', 'Parse', 'PrintMessage', 'PrintField', - 'PrintFieldValue', 'Merge', 'MessageToBytes'] - -_INTEGER_CHECKERS = (type_checkers.Uint32ValueChecker(), - type_checkers.Int32ValueChecker(), - type_checkers.Uint64ValueChecker(), - type_checkers.Int64ValueChecker()) -_FLOAT_INFINITY = re.compile('-?inf(?:inity)?f?$', re.IGNORECASE) -_FLOAT_NAN = re.compile('nanf?$', re.IGNORECASE) -_QUOTES = frozenset(("'", '"')) -_ANY_FULL_TYPE_NAME = 'google.protobuf.Any' - - -class Error(Exception): - """Top-level module error for text_format.""" - - -class ParseError(Error): - """Thrown in case of text parsing or tokenizing error.""" - - def __init__(self, message=None, line=None, column=None): - if message is not None and line is not None: - loc = str(line) - if column is not None: - loc += ':{0}'.format(column) - message = '{0} : {1}'.format(loc, message) - if message is not None: - super(ParseError, self).__init__(message) - else: - super(ParseError, self).__init__() - self._line = line - self._column = column - - def GetLine(self): - return self._line - - def GetColumn(self): - return self._column - - -class TextWriter(object): - - def __init__(self, as_utf8): - self._writer = io.StringIO() - - def write(self, val): - return self._writer.write(val) - - def close(self): - return self._writer.close() - - def getvalue(self): - return self._writer.getvalue() - - -def MessageToString( - message, - as_utf8=False, - as_one_line=False, - use_short_repeated_primitives=False, - pointy_brackets=False, - use_index_order=False, - float_format=None, - double_format=None, - use_field_number=False, - descriptor_pool=None, - indent=0, - message_formatter=None, - print_unknown_fields=False, - force_colon=False): - # type: (...) -> str - """Convert protobuf message to text format. - - Double values can be formatted compactly with 15 digits of - precision (which is the most that IEEE 754 "double" can guarantee) - using double_format='.15g'. To ensure that converting to text and back to a - proto will result in an identical value, double_format='.17g' should be used. - - Args: - message: The protocol buffers message. - as_utf8: Return unescaped Unicode for non-ASCII characters. - In Python 3 actual Unicode characters may appear as is in strings. - In Python 2 the return value will be valid UTF-8 rather than only ASCII. - as_one_line: Don't introduce newlines between fields. - use_short_repeated_primitives: Use short repeated format for primitives. - pointy_brackets: If True, use angle brackets instead of curly braces for - nesting. - use_index_order: If True, fields of a proto message will be printed using - the order defined in source code instead of the field number, extensions - will be printed at the end of the message and their relative order is - determined by the extension number. By default, use the field number - order. - float_format (str): If set, use this to specify float field formatting - (per the "Format Specification Mini-Language"); otherwise, shortest float - that has same value in wire will be printed. Also affect double field - if double_format is not set but float_format is set. - double_format (str): If set, use this to specify double field formatting - (per the "Format Specification Mini-Language"); if it is not set but - float_format is set, use float_format. Otherwise, use ``str()`` - use_field_number: If True, print field numbers instead of names. - descriptor_pool (DescriptorPool): Descriptor pool used to resolve Any types. - indent (int): The initial indent level, in terms of spaces, for pretty - print. - message_formatter (function(message, indent, as_one_line) -> unicode|None): - Custom formatter for selected sub-messages (usually based on message - type). Use to pretty print parts of the protobuf for easier diffing. - print_unknown_fields: If True, unknown fields will be printed. - force_colon: If set, a colon will be added after the field name even if the - field is a proto message. - - Returns: - str: A string of the text formatted protocol buffer message. - """ - out = TextWriter(as_utf8) - printer = _Printer( - out, - indent, - as_utf8, - as_one_line, - use_short_repeated_primitives, - pointy_brackets, - use_index_order, - float_format, - double_format, - use_field_number, - descriptor_pool, - message_formatter, - print_unknown_fields=print_unknown_fields, - force_colon=force_colon) - printer.PrintMessage(message) - result = out.getvalue() - out.close() - if as_one_line: - return result.rstrip() - return result - - -def MessageToBytes(message, **kwargs): - # type: (...) -> bytes - """Convert protobuf message to encoded text format. See MessageToString.""" - text = MessageToString(message, **kwargs) - if isinstance(text, bytes): - return text - codec = 'utf-8' if kwargs.get('as_utf8') else 'ascii' - return text.encode(codec) - - -def _IsMapEntry(field): - return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and - field.message_type.has_options and - field.message_type.GetOptions().map_entry) - - -def PrintMessage(message, - out, - indent=0, - as_utf8=False, - as_one_line=False, - use_short_repeated_primitives=False, - pointy_brackets=False, - use_index_order=False, - float_format=None, - double_format=None, - use_field_number=False, - descriptor_pool=None, - message_formatter=None, - print_unknown_fields=False, - force_colon=False): - printer = _Printer( - out=out, indent=indent, as_utf8=as_utf8, - as_one_line=as_one_line, - use_short_repeated_primitives=use_short_repeated_primitives, - pointy_brackets=pointy_brackets, - use_index_order=use_index_order, - float_format=float_format, - double_format=double_format, - use_field_number=use_field_number, - descriptor_pool=descriptor_pool, - message_formatter=message_formatter, - print_unknown_fields=print_unknown_fields, - force_colon=force_colon) - printer.PrintMessage(message) - - -def PrintField(field, - value, - out, - indent=0, - as_utf8=False, - as_one_line=False, - use_short_repeated_primitives=False, - pointy_brackets=False, - use_index_order=False, - float_format=None, - double_format=None, - message_formatter=None, - print_unknown_fields=False, - force_colon=False): - """Print a single field name/value pair.""" - printer = _Printer(out, indent, as_utf8, as_one_line, - use_short_repeated_primitives, pointy_brackets, - use_index_order, float_format, double_format, - message_formatter=message_formatter, - print_unknown_fields=print_unknown_fields, - force_colon=force_colon) - printer.PrintField(field, value) - - -def PrintFieldValue(field, - value, - out, - indent=0, - as_utf8=False, - as_one_line=False, - use_short_repeated_primitives=False, - pointy_brackets=False, - use_index_order=False, - float_format=None, - double_format=None, - message_formatter=None, - print_unknown_fields=False, - force_colon=False): - """Print a single field value (not including name).""" - printer = _Printer(out, indent, as_utf8, as_one_line, - use_short_repeated_primitives, pointy_brackets, - use_index_order, float_format, double_format, - message_formatter=message_formatter, - print_unknown_fields=print_unknown_fields, - force_colon=force_colon) - printer.PrintFieldValue(field, value) - - -def _BuildMessageFromTypeName(type_name, descriptor_pool): - """Returns a protobuf message instance. - - Args: - type_name: Fully-qualified protobuf message type name string. - descriptor_pool: DescriptorPool instance. - - Returns: - A Message instance of type matching type_name, or None if the a Descriptor - wasn't found matching type_name. - """ - # pylint: disable=g-import-not-at-top - if descriptor_pool is None: - from google.protobuf import descriptor_pool as pool_mod - descriptor_pool = pool_mod.Default() - from google.protobuf import symbol_database - database = symbol_database.Default() - try: - message_descriptor = descriptor_pool.FindMessageTypeByName(type_name) - except KeyError: - return None - message_type = database.GetPrototype(message_descriptor) - return message_type() - - -# These values must match WireType enum in google/protobuf/wire_format.h. -WIRETYPE_LENGTH_DELIMITED = 2 -WIRETYPE_START_GROUP = 3 - - -class _Printer(object): - """Text format printer for protocol message.""" - - def __init__( - self, - out, - indent=0, - as_utf8=False, - as_one_line=False, - use_short_repeated_primitives=False, - pointy_brackets=False, - use_index_order=False, - float_format=None, - double_format=None, - use_field_number=False, - descriptor_pool=None, - message_formatter=None, - print_unknown_fields=False, - force_colon=False): - """Initialize the Printer. - - Double values can be formatted compactly with 15 digits of precision - (which is the most that IEEE 754 "double" can guarantee) using - double_format='.15g'. To ensure that converting to text and back to a proto - will result in an identical value, double_format='.17g' should be used. - - Args: - out: To record the text format result. - indent: The initial indent level for pretty print. - as_utf8: Return unescaped Unicode for non-ASCII characters. - In Python 3 actual Unicode characters may appear as is in strings. - In Python 2 the return value will be valid UTF-8 rather than ASCII. - as_one_line: Don't introduce newlines between fields. - use_short_repeated_primitives: Use short repeated format for primitives. - pointy_brackets: If True, use angle brackets instead of curly braces for - nesting. - use_index_order: If True, print fields of a proto message using the order - defined in source code instead of the field number. By default, use the - field number order. - float_format: If set, use this to specify float field formatting - (per the "Format Specification Mini-Language"); otherwise, shortest - float that has same value in wire will be printed. Also affect double - field if double_format is not set but float_format is set. - double_format: If set, use this to specify double field formatting - (per the "Format Specification Mini-Language"); if it is not set but - float_format is set, use float_format. Otherwise, str() is used. - use_field_number: If True, print field numbers instead of names. - descriptor_pool: A DescriptorPool used to resolve Any types. - message_formatter: A function(message, indent, as_one_line): unicode|None - to custom format selected sub-messages (usually based on message type). - Use to pretty print parts of the protobuf for easier diffing. - print_unknown_fields: If True, unknown fields will be printed. - force_colon: If set, a colon will be added after the field name even if - the field is a proto message. - """ - self.out = out - self.indent = indent - self.as_utf8 = as_utf8 - self.as_one_line = as_one_line - self.use_short_repeated_primitives = use_short_repeated_primitives - self.pointy_brackets = pointy_brackets - self.use_index_order = use_index_order - self.float_format = float_format - if double_format is not None: - self.double_format = double_format - else: - self.double_format = float_format - self.use_field_number = use_field_number - self.descriptor_pool = descriptor_pool - self.message_formatter = message_formatter - self.print_unknown_fields = print_unknown_fields - self.force_colon = force_colon - - def _TryPrintAsAnyMessage(self, message): - """Serializes if message is a google.protobuf.Any field.""" - if '/' not in message.type_url: - return False - packed_message = _BuildMessageFromTypeName(message.TypeName(), - self.descriptor_pool) - if packed_message: - packed_message.MergeFromString(message.value) - colon = ':' if self.force_colon else '' - self.out.write('%s[%s]%s ' % (self.indent * ' ', message.type_url, colon)) - self._PrintMessageFieldValue(packed_message) - self.out.write(' ' if self.as_one_line else '\n') - return True - else: - return False - - def _TryCustomFormatMessage(self, message): - formatted = self.message_formatter(message, self.indent, self.as_one_line) - if formatted is None: - return False - - out = self.out - out.write(' ' * self.indent) - out.write(formatted) - out.write(' ' if self.as_one_line else '\n') - return True - - def PrintMessage(self, message): - """Convert protobuf message to text format. - - Args: - message: The protocol buffers message. - """ - if self.message_formatter and self._TryCustomFormatMessage(message): - return - if (message.DESCRIPTOR.full_name == _ANY_FULL_TYPE_NAME and - self._TryPrintAsAnyMessage(message)): - return - fields = message.ListFields() - if self.use_index_order: - fields.sort( - key=lambda x: x[0].number if x[0].is_extension else x[0].index) - for field, value in fields: - if _IsMapEntry(field): - for key in sorted(value): - # This is slow for maps with submessage entries because it copies the - # entire tree. Unfortunately this would take significant refactoring - # of this file to work around. - # - # TODO(haberman): refactor and optimize if this becomes an issue. - entry_submsg = value.GetEntryClass()(key=key, value=value[key]) - self.PrintField(field, entry_submsg) - elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - if (self.use_short_repeated_primitives - and field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE - and field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_STRING): - self._PrintShortRepeatedPrimitivesValue(field, value) - else: - for element in value: - self.PrintField(field, element) - else: - self.PrintField(field, value) - - if self.print_unknown_fields: - self._PrintUnknownFields(message.UnknownFields()) - - def _PrintUnknownFields(self, unknown_fields): - """Print unknown fields.""" - out = self.out - for field in unknown_fields: - out.write(' ' * self.indent) - out.write(str(field.field_number)) - if field.wire_type == WIRETYPE_START_GROUP: - if self.as_one_line: - out.write(' { ') - else: - out.write(' {\n') - self.indent += 2 - - self._PrintUnknownFields(field.data) - - if self.as_one_line: - out.write('} ') - else: - self.indent -= 2 - out.write(' ' * self.indent + '}\n') - elif field.wire_type == WIRETYPE_LENGTH_DELIMITED: - try: - # If this field is parseable as a Message, it is probably - # an embedded message. - # pylint: disable=protected-access - (embedded_unknown_message, pos) = decoder._DecodeUnknownFieldSet( - memoryview(field.data), 0, len(field.data)) - except Exception: # pylint: disable=broad-except - pos = 0 - - if pos == len(field.data): - if self.as_one_line: - out.write(' { ') - else: - out.write(' {\n') - self.indent += 2 - - self._PrintUnknownFields(embedded_unknown_message) - - if self.as_one_line: - out.write('} ') - else: - self.indent -= 2 - out.write(' ' * self.indent + '}\n') - else: - # A string or bytes field. self.as_utf8 may not work. - out.write(': \"') - out.write(text_encoding.CEscape(field.data, False)) - out.write('\" ' if self.as_one_line else '\"\n') - else: - # varint, fixed32, fixed64 - out.write(': ') - out.write(str(field.data)) - out.write(' ' if self.as_one_line else '\n') - - def _PrintFieldName(self, field): - """Print field name.""" - out = self.out - out.write(' ' * self.indent) - if self.use_field_number: - out.write(str(field.number)) - else: - if field.is_extension: - out.write('[') - if (field.containing_type.GetOptions().message_set_wire_format and - field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and - field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL): - out.write(field.message_type.full_name) - else: - out.write(field.full_name) - out.write(']') - elif field.type == descriptor.FieldDescriptor.TYPE_GROUP: - # For groups, use the capitalized name. - out.write(field.message_type.name) - else: - out.write(field.name) - - if (self.force_colon or - field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE): - # The colon is optional in this case, but our cross-language golden files - # don't include it. Here, the colon is only included if force_colon is - # set to True - out.write(':') - - def PrintField(self, field, value): - """Print a single field name/value pair.""" - self._PrintFieldName(field) - self.out.write(' ') - self.PrintFieldValue(field, value) - self.out.write(' ' if self.as_one_line else '\n') - - def _PrintShortRepeatedPrimitivesValue(self, field, value): - """"Prints short repeated primitives value.""" - # Note: this is called only when value has at least one element. - self._PrintFieldName(field) - self.out.write(' [') - for i in range(len(value) - 1): - self.PrintFieldValue(field, value[i]) - self.out.write(', ') - self.PrintFieldValue(field, value[-1]) - self.out.write(']') - self.out.write(' ' if self.as_one_line else '\n') - - def _PrintMessageFieldValue(self, value): - if self.pointy_brackets: - openb = '<' - closeb = '>' - else: - openb = '{' - closeb = '}' - - if self.as_one_line: - self.out.write('%s ' % openb) - self.PrintMessage(value) - self.out.write(closeb) - else: - self.out.write('%s\n' % openb) - self.indent += 2 - self.PrintMessage(value) - self.indent -= 2 - self.out.write(' ' * self.indent + closeb) - - def PrintFieldValue(self, field, value): - """Print a single field value (not including name). - - For repeated fields, the value should be a single element. - - Args: - field: The descriptor of the field to be printed. - value: The value of the field. - """ - out = self.out - if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - self._PrintMessageFieldValue(value) - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: - enum_value = field.enum_type.values_by_number.get(value, None) - if enum_value is not None: - out.write(enum_value.name) - else: - out.write(str(value)) - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: - out.write('\"') - if isinstance(value, str) and not self.as_utf8: - out_value = value.encode('utf-8') - else: - out_value = value - if field.type == descriptor.FieldDescriptor.TYPE_BYTES: - # We always need to escape all binary data in TYPE_BYTES fields. - out_as_utf8 = False - else: - out_as_utf8 = self.as_utf8 - out.write(text_encoding.CEscape(out_value, out_as_utf8)) - out.write('\"') - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: - if value: - out.write('true') - else: - out.write('false') - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT: - if self.float_format is not None: - out.write('{1:{0}}'.format(self.float_format, value)) - else: - if math.isnan(value): - out.write(str(value)) - else: - out.write(str(type_checkers.ToShortestFloat(value))) - elif (field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_DOUBLE and - self.double_format is not None): - out.write('{1:{0}}'.format(self.double_format, value)) - else: - out.write(str(value)) - - -def Parse(text, - message, - allow_unknown_extension=False, - allow_field_number=False, - descriptor_pool=None, - allow_unknown_field=False): - """Parses a text representation of a protocol message into a message. - - NOTE: for historical reasons this function does not clear the input - message. This is different from what the binary msg.ParseFrom(...) does. - If text contains a field already set in message, the value is appended if the - field is repeated. Otherwise, an error is raised. - - Example:: - - a = MyProto() - a.repeated_field.append('test') - b = MyProto() - - # Repeated fields are combined - text_format.Parse(repr(a), b) - text_format.Parse(repr(a), b) # repeated_field contains ["test", "test"] - - # Non-repeated fields cannot be overwritten - a.singular_field = 1 - b.singular_field = 2 - text_format.Parse(repr(a), b) # ParseError - - # Binary version: - b.ParseFromString(a.SerializeToString()) # repeated_field is now "test" - - Caller is responsible for clearing the message as needed. - - Args: - text (str): Message text representation. - message (Message): A protocol buffer message to merge into. - allow_unknown_extension: if True, skip over missing extensions and keep - parsing - allow_field_number: if True, both field number and field name are allowed. - descriptor_pool (DescriptorPool): Descriptor pool used to resolve Any types. - allow_unknown_field: if True, skip over unknown field and keep - parsing. Avoid to use this option if possible. It may hide some - errors (e.g. spelling error on field name) - - Returns: - Message: The same message passed as argument. - - Raises: - ParseError: On text parsing problems. - """ - return ParseLines(text.split(b'\n' if isinstance(text, bytes) else u'\n'), - message, - allow_unknown_extension, - allow_field_number, - descriptor_pool=descriptor_pool, - allow_unknown_field=allow_unknown_field) - - -def Merge(text, - message, - allow_unknown_extension=False, - allow_field_number=False, - descriptor_pool=None, - allow_unknown_field=False): - """Parses a text representation of a protocol message into a message. - - Like Parse(), but allows repeated values for a non-repeated field, and uses - the last one. This means any non-repeated, top-level fields specified in text - replace those in the message. - - Args: - text (str): Message text representation. - message (Message): A protocol buffer message to merge into. - allow_unknown_extension: if True, skip over missing extensions and keep - parsing - allow_field_number: if True, both field number and field name are allowed. - descriptor_pool (DescriptorPool): Descriptor pool used to resolve Any types. - allow_unknown_field: if True, skip over unknown field and keep - parsing. Avoid to use this option if possible. It may hide some - errors (e.g. spelling error on field name) - - Returns: - Message: The same message passed as argument. - - Raises: - ParseError: On text parsing problems. - """ - return MergeLines( - text.split(b'\n' if isinstance(text, bytes) else u'\n'), - message, - allow_unknown_extension, - allow_field_number, - descriptor_pool=descriptor_pool, - allow_unknown_field=allow_unknown_field) - - -def ParseLines(lines, - message, - allow_unknown_extension=False, - allow_field_number=False, - descriptor_pool=None, - allow_unknown_field=False): - """Parses a text representation of a protocol message into a message. - - See Parse() for caveats. - - Args: - lines: An iterable of lines of a message's text representation. - message: A protocol buffer message to merge into. - allow_unknown_extension: if True, skip over missing extensions and keep - parsing - allow_field_number: if True, both field number and field name are allowed. - descriptor_pool: A DescriptorPool used to resolve Any types. - allow_unknown_field: if True, skip over unknown field and keep - parsing. Avoid to use this option if possible. It may hide some - errors (e.g. spelling error on field name) - - Returns: - The same message passed as argument. - - Raises: - ParseError: On text parsing problems. - """ - parser = _Parser(allow_unknown_extension, - allow_field_number, - descriptor_pool=descriptor_pool, - allow_unknown_field=allow_unknown_field) - return parser.ParseLines(lines, message) - - -def MergeLines(lines, - message, - allow_unknown_extension=False, - allow_field_number=False, - descriptor_pool=None, - allow_unknown_field=False): - """Parses a text representation of a protocol message into a message. - - See Merge() for more details. - - Args: - lines: An iterable of lines of a message's text representation. - message: A protocol buffer message to merge into. - allow_unknown_extension: if True, skip over missing extensions and keep - parsing - allow_field_number: if True, both field number and field name are allowed. - descriptor_pool: A DescriptorPool used to resolve Any types. - allow_unknown_field: if True, skip over unknown field and keep - parsing. Avoid to use this option if possible. It may hide some - errors (e.g. spelling error on field name) - - Returns: - The same message passed as argument. - - Raises: - ParseError: On text parsing problems. - """ - parser = _Parser(allow_unknown_extension, - allow_field_number, - descriptor_pool=descriptor_pool, - allow_unknown_field=allow_unknown_field) - return parser.MergeLines(lines, message) - - -class _Parser(object): - """Text format parser for protocol message.""" - - def __init__(self, - allow_unknown_extension=False, - allow_field_number=False, - descriptor_pool=None, - allow_unknown_field=False): - self.allow_unknown_extension = allow_unknown_extension - self.allow_field_number = allow_field_number - self.descriptor_pool = descriptor_pool - self.allow_unknown_field = allow_unknown_field - - def ParseLines(self, lines, message): - """Parses a text representation of a protocol message into a message.""" - self._allow_multiple_scalars = False - self._ParseOrMerge(lines, message) - return message - - def MergeLines(self, lines, message): - """Merges a text representation of a protocol message into a message.""" - self._allow_multiple_scalars = True - self._ParseOrMerge(lines, message) - return message - - def _ParseOrMerge(self, lines, message): - """Converts a text representation of a protocol message into a message. - - Args: - lines: Lines of a message's text representation. - message: A protocol buffer message to merge into. - - Raises: - ParseError: On text parsing problems. - """ - # Tokenize expects native str lines. - str_lines = ( - line if isinstance(line, str) else line.decode('utf-8') - for line in lines) - tokenizer = Tokenizer(str_lines) - while not tokenizer.AtEnd(): - self._MergeField(tokenizer, message) - - def _MergeField(self, tokenizer, message): - """Merges a single protocol message field into a message. - - Args: - tokenizer: A tokenizer to parse the field name and values. - message: A protocol message to record the data. - - Raises: - ParseError: In case of text parsing problems. - """ - message_descriptor = message.DESCRIPTOR - if (message_descriptor.full_name == _ANY_FULL_TYPE_NAME and - tokenizer.TryConsume('[')): - type_url_prefix, packed_type_name = self._ConsumeAnyTypeUrl(tokenizer) - tokenizer.Consume(']') - tokenizer.TryConsume(':') - if tokenizer.TryConsume('<'): - expanded_any_end_token = '>' - else: - tokenizer.Consume('{') - expanded_any_end_token = '}' - expanded_any_sub_message = _BuildMessageFromTypeName(packed_type_name, - self.descriptor_pool) - if not expanded_any_sub_message: - raise ParseError('Type %s not found in descriptor pool' % - packed_type_name) - while not tokenizer.TryConsume(expanded_any_end_token): - if tokenizer.AtEnd(): - raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % - (expanded_any_end_token,)) - self._MergeField(tokenizer, expanded_any_sub_message) - deterministic = False - - message.Pack(expanded_any_sub_message, - type_url_prefix=type_url_prefix, - deterministic=deterministic) - return - - if tokenizer.TryConsume('['): - name = [tokenizer.ConsumeIdentifier()] - while tokenizer.TryConsume('.'): - name.append(tokenizer.ConsumeIdentifier()) - name = '.'.join(name) - - if not message_descriptor.is_extendable: - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" does not have extensions.' % - message_descriptor.full_name) - # pylint: disable=protected-access - field = message.Extensions._FindExtensionByName(name) - # pylint: enable=protected-access - - - if not field: - if self.allow_unknown_extension: - field = None - else: - raise tokenizer.ParseErrorPreviousToken( - 'Extension "%s" not registered. ' - 'Did you import the _pb2 module which defines it? ' - 'If you are trying to place the extension in the MessageSet ' - 'field of another message that is in an Any or MessageSet field, ' - 'that message\'s _pb2 module must be imported as well' % name) - elif message_descriptor != field.containing_type: - raise tokenizer.ParseErrorPreviousToken( - 'Extension "%s" does not extend message type "%s".' % - (name, message_descriptor.full_name)) - - tokenizer.Consume(']') - - else: - name = tokenizer.ConsumeIdentifierOrNumber() - if self.allow_field_number and name.isdigit(): - number = ParseInteger(name, True, True) - field = message_descriptor.fields_by_number.get(number, None) - if not field and message_descriptor.is_extendable: - field = message.Extensions._FindExtensionByNumber(number) - else: - field = message_descriptor.fields_by_name.get(name, None) - - # Group names are expected to be capitalized as they appear in the - # .proto file, which actually matches their type names, not their field - # names. - if not field: - field = message_descriptor.fields_by_name.get(name.lower(), None) - if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP: - field = None - - if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and - field.message_type.name != name): - field = None - - if not field and not self.allow_unknown_field: - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" has no field named "%s".' % - (message_descriptor.full_name, name)) - - if field: - if not self._allow_multiple_scalars and field.containing_oneof: - # Check if there's a different field set in this oneof. - # Note that we ignore the case if the same field was set before, and we - # apply _allow_multiple_scalars to non-scalar fields as well. - which_oneof = message.WhichOneof(field.containing_oneof.name) - if which_oneof is not None and which_oneof != field.name: - raise tokenizer.ParseErrorPreviousToken( - 'Field "%s" is specified along with field "%s", another member ' - 'of oneof "%s" for message type "%s".' % - (field.name, which_oneof, field.containing_oneof.name, - message_descriptor.full_name)) - - if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - tokenizer.TryConsume(':') - merger = self._MergeMessageField - else: - tokenizer.Consume(':') - merger = self._MergeScalarField - - if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and - tokenizer.TryConsume('[')): - # Short repeated format, e.g. "foo: [1, 2, 3]" - if not tokenizer.TryConsume(']'): - while True: - merger(tokenizer, message, field) - if tokenizer.TryConsume(']'): - break - tokenizer.Consume(',') - - else: - merger(tokenizer, message, field) - - else: # Proto field is unknown. - assert (self.allow_unknown_extension or self.allow_unknown_field) - _SkipFieldContents(tokenizer) - - # For historical reasons, fields may optionally be separated by commas or - # semicolons. - if not tokenizer.TryConsume(','): - tokenizer.TryConsume(';') - - - def _ConsumeAnyTypeUrl(self, tokenizer): - """Consumes a google.protobuf.Any type URL and returns the type name.""" - # Consume "type.googleapis.com/". - prefix = [tokenizer.ConsumeIdentifier()] - tokenizer.Consume('.') - prefix.append(tokenizer.ConsumeIdentifier()) - tokenizer.Consume('.') - prefix.append(tokenizer.ConsumeIdentifier()) - tokenizer.Consume('/') - # Consume the fully-qualified type name. - name = [tokenizer.ConsumeIdentifier()] - while tokenizer.TryConsume('.'): - name.append(tokenizer.ConsumeIdentifier()) - return '.'.join(prefix), '.'.join(name) - - def _MergeMessageField(self, tokenizer, message, field): - """Merges a single scalar field into a message. - - Args: - tokenizer: A tokenizer to parse the field value. - message: The message of which field is a member. - field: The descriptor of the field to be merged. - - Raises: - ParseError: In case of text parsing problems. - """ - is_map_entry = _IsMapEntry(field) - - if tokenizer.TryConsume('<'): - end_token = '>' - else: - tokenizer.Consume('{') - end_token = '}' - - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - if field.is_extension: - sub_message = message.Extensions[field].add() - elif is_map_entry: - sub_message = getattr(message, field.name).GetEntryClass()() - else: - sub_message = getattr(message, field.name).add() - else: - if field.is_extension: - if (not self._allow_multiple_scalars and - message.HasExtension(field)): - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" should not have multiple "%s" extensions.' % - (message.DESCRIPTOR.full_name, field.full_name)) - sub_message = message.Extensions[field] - else: - # Also apply _allow_multiple_scalars to message field. - # TODO(jieluo): Change to _allow_singular_overwrites. - if (not self._allow_multiple_scalars and - message.HasField(field.name)): - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" should not have multiple "%s" fields.' % - (message.DESCRIPTOR.full_name, field.name)) - sub_message = getattr(message, field.name) - sub_message.SetInParent() - - while not tokenizer.TryConsume(end_token): - if tokenizer.AtEnd(): - raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token,)) - self._MergeField(tokenizer, sub_message) - - if is_map_entry: - value_cpptype = field.message_type.fields_by_name['value'].cpp_type - if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - value = getattr(message, field.name)[sub_message.key] - value.CopyFrom(sub_message.value) - else: - getattr(message, field.name)[sub_message.key] = sub_message.value - - @staticmethod - def _IsProto3Syntax(message): - message_descriptor = message.DESCRIPTOR - return (hasattr(message_descriptor, 'syntax') and - message_descriptor.syntax == 'proto3') - - def _MergeScalarField(self, tokenizer, message, field): - """Merges a single scalar field into a message. - - Args: - tokenizer: A tokenizer to parse the field value. - message: A protocol message to record the data. - field: The descriptor of the field to be merged. - - Raises: - ParseError: In case of text parsing problems. - RuntimeError: On runtime errors. - """ - _ = self.allow_unknown_extension - value = None - - if field.type in (descriptor.FieldDescriptor.TYPE_INT32, - descriptor.FieldDescriptor.TYPE_SINT32, - descriptor.FieldDescriptor.TYPE_SFIXED32): - value = _ConsumeInt32(tokenizer) - elif field.type in (descriptor.FieldDescriptor.TYPE_INT64, - descriptor.FieldDescriptor.TYPE_SINT64, - descriptor.FieldDescriptor.TYPE_SFIXED64): - value = _ConsumeInt64(tokenizer) - elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32, - descriptor.FieldDescriptor.TYPE_FIXED32): - value = _ConsumeUint32(tokenizer) - elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64, - descriptor.FieldDescriptor.TYPE_FIXED64): - value = _ConsumeUint64(tokenizer) - elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT, - descriptor.FieldDescriptor.TYPE_DOUBLE): - value = tokenizer.ConsumeFloat() - elif field.type == descriptor.FieldDescriptor.TYPE_BOOL: - value = tokenizer.ConsumeBool() - elif field.type == descriptor.FieldDescriptor.TYPE_STRING: - value = tokenizer.ConsumeString() - elif field.type == descriptor.FieldDescriptor.TYPE_BYTES: - value = tokenizer.ConsumeByteString() - elif field.type == descriptor.FieldDescriptor.TYPE_ENUM: - value = tokenizer.ConsumeEnum(field) - else: - raise RuntimeError('Unknown field type %d' % field.type) - - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - if field.is_extension: - message.Extensions[field].append(value) - else: - getattr(message, field.name).append(value) - else: - if field.is_extension: - if (not self._allow_multiple_scalars and - not self._IsProto3Syntax(message) and - message.HasExtension(field)): - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" should not have multiple "%s" extensions.' % - (message.DESCRIPTOR.full_name, field.full_name)) - else: - message.Extensions[field] = value - else: - duplicate_error = False - if not self._allow_multiple_scalars: - if self._IsProto3Syntax(message): - # Proto3 doesn't represent presence so we try best effort to check - # multiple scalars by compare to default values. - duplicate_error = bool(getattr(message, field.name)) - else: - duplicate_error = message.HasField(field.name) - - if duplicate_error: - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" should not have multiple "%s" fields.' % - (message.DESCRIPTOR.full_name, field.name)) - else: - setattr(message, field.name, value) - - -def _SkipFieldContents(tokenizer): - """Skips over contents (value or message) of a field. - - Args: - tokenizer: A tokenizer to parse the field name and values. - """ - # Try to guess the type of this field. - # If this field is not a message, there should be a ":" between the - # field name and the field value and also the field value should not - # start with "{" or "<" which indicates the beginning of a message body. - # If there is no ":" or there is a "{" or "<" after ":", this field has - # to be a message or the input is ill-formed. - if tokenizer.TryConsume(':') and not tokenizer.LookingAt( - '{') and not tokenizer.LookingAt('<'): - _SkipFieldValue(tokenizer) - else: - _SkipFieldMessage(tokenizer) - - -def _SkipField(tokenizer): - """Skips over a complete field (name and value/message). - - Args: - tokenizer: A tokenizer to parse the field name and values. - """ - if tokenizer.TryConsume('['): - # Consume extension name. - tokenizer.ConsumeIdentifier() - while tokenizer.TryConsume('.'): - tokenizer.ConsumeIdentifier() - tokenizer.Consume(']') - else: - tokenizer.ConsumeIdentifierOrNumber() - - _SkipFieldContents(tokenizer) - - # For historical reasons, fields may optionally be separated by commas or - # semicolons. - if not tokenizer.TryConsume(','): - tokenizer.TryConsume(';') - - -def _SkipFieldMessage(tokenizer): - """Skips over a field message. - - Args: - tokenizer: A tokenizer to parse the field name and values. - """ - - if tokenizer.TryConsume('<'): - delimiter = '>' - else: - tokenizer.Consume('{') - delimiter = '}' - - while not tokenizer.LookingAt('>') and not tokenizer.LookingAt('}'): - _SkipField(tokenizer) - - tokenizer.Consume(delimiter) - - -def _SkipFieldValue(tokenizer): - """Skips over a field value. - - Args: - tokenizer: A tokenizer to parse the field name and values. - - Raises: - ParseError: In case an invalid field value is found. - """ - # String/bytes tokens can come in multiple adjacent string literals. - # If we can consume one, consume as many as we can. - if tokenizer.TryConsumeByteString(): - while tokenizer.TryConsumeByteString(): - pass - return - - if (not tokenizer.TryConsumeIdentifier() and - not _TryConsumeInt64(tokenizer) and not _TryConsumeUint64(tokenizer) and - not tokenizer.TryConsumeFloat()): - raise ParseError('Invalid field value: ' + tokenizer.token) - - -class Tokenizer(object): - """Protocol buffer text representation tokenizer. - - This class handles the lower level string parsing by splitting it into - meaningful tokens. - - It was directly ported from the Java protocol buffer API. - """ - - _WHITESPACE = re.compile(r'\s+') - _COMMENT = re.compile(r'(\s*#.*$)', re.MULTILINE) - _WHITESPACE_OR_COMMENT = re.compile(r'(\s|(#.*$))+', re.MULTILINE) - _TOKEN = re.compile('|'.join([ - r'[a-zA-Z_][0-9a-zA-Z_+-]*', # an identifier - r'([0-9+-]|(\.[0-9]))[0-9a-zA-Z_.+-]*', # a number - ] + [ # quoted str for each quote mark - # Avoid backtracking! https://stackoverflow.com/a/844267 - r'{qt}[^{qt}\n\\]*((\\.)+[^{qt}\n\\]*)*({qt}|\\?$)'.format(qt=mark) - for mark in _QUOTES - ])) - - _IDENTIFIER = re.compile(r'[^\d\W]\w*') - _IDENTIFIER_OR_NUMBER = re.compile(r'\w+') - - def __init__(self, lines, skip_comments=True): - self._position = 0 - self._line = -1 - self._column = 0 - self._token_start = None - self.token = '' - self._lines = iter(lines) - self._current_line = '' - self._previous_line = 0 - self._previous_column = 0 - self._more_lines = True - self._skip_comments = skip_comments - self._whitespace_pattern = (skip_comments and self._WHITESPACE_OR_COMMENT - or self._WHITESPACE) - self._SkipWhitespace() - self.NextToken() - - def LookingAt(self, token): - return self.token == token - - def AtEnd(self): - """Checks the end of the text was reached. - - Returns: - True iff the end was reached. - """ - return not self.token - - def _PopLine(self): - while len(self._current_line) <= self._column: - try: - self._current_line = next(self._lines) - except StopIteration: - self._current_line = '' - self._more_lines = False - return - else: - self._line += 1 - self._column = 0 - - def _SkipWhitespace(self): - while True: - self._PopLine() - match = self._whitespace_pattern.match(self._current_line, self._column) - if not match: - break - length = len(match.group(0)) - self._column += length - - def TryConsume(self, token): - """Tries to consume a given piece of text. - - Args: - token: Text to consume. - - Returns: - True iff the text was consumed. - """ - if self.token == token: - self.NextToken() - return True - return False - - def Consume(self, token): - """Consumes a piece of text. - - Args: - token: Text to consume. - - Raises: - ParseError: If the text couldn't be consumed. - """ - if not self.TryConsume(token): - raise self.ParseError('Expected "%s".' % token) - - def ConsumeComment(self): - result = self.token - if not self._COMMENT.match(result): - raise self.ParseError('Expected comment.') - self.NextToken() - return result - - def ConsumeCommentOrTrailingComment(self): - """Consumes a comment, returns a 2-tuple (trailing bool, comment str).""" - - # Tokenizer initializes _previous_line and _previous_column to 0. As the - # tokenizer starts, it looks like there is a previous token on the line. - just_started = self._line == 0 and self._column == 0 - - before_parsing = self._previous_line - comment = self.ConsumeComment() - - # A trailing comment is a comment on the same line than the previous token. - trailing = (self._previous_line == before_parsing - and not just_started) - - return trailing, comment - - def TryConsumeIdentifier(self): - try: - self.ConsumeIdentifier() - return True - except ParseError: - return False - - def ConsumeIdentifier(self): - """Consumes protocol message field identifier. - - Returns: - Identifier string. - - Raises: - ParseError: If an identifier couldn't be consumed. - """ - result = self.token - if not self._IDENTIFIER.match(result): - raise self.ParseError('Expected identifier.') - self.NextToken() - return result - - def TryConsumeIdentifierOrNumber(self): - try: - self.ConsumeIdentifierOrNumber() - return True - except ParseError: - return False - - def ConsumeIdentifierOrNumber(self): - """Consumes protocol message field identifier. - - Returns: - Identifier string. - - Raises: - ParseError: If an identifier couldn't be consumed. - """ - result = self.token - if not self._IDENTIFIER_OR_NUMBER.match(result): - raise self.ParseError('Expected identifier or number, got %s.' % result) - self.NextToken() - return result - - def TryConsumeInteger(self): - try: - self.ConsumeInteger() - return True - except ParseError: - return False - - def ConsumeInteger(self): - """Consumes an integer number. - - Returns: - The integer parsed. - - Raises: - ParseError: If an integer couldn't be consumed. - """ - try: - result = _ParseAbstractInteger(self.token) - except ValueError as e: - raise self.ParseError(str(e)) - self.NextToken() - return result - - def TryConsumeFloat(self): - try: - self.ConsumeFloat() - return True - except ParseError: - return False - - def ConsumeFloat(self): - """Consumes an floating point number. - - Returns: - The number parsed. - - Raises: - ParseError: If a floating point number couldn't be consumed. - """ - try: - result = ParseFloat(self.token) - except ValueError as e: - raise self.ParseError(str(e)) - self.NextToken() - return result - - def ConsumeBool(self): - """Consumes a boolean value. - - Returns: - The bool parsed. - - Raises: - ParseError: If a boolean value couldn't be consumed. - """ - try: - result = ParseBool(self.token) - except ValueError as e: - raise self.ParseError(str(e)) - self.NextToken() - return result - - def TryConsumeByteString(self): - try: - self.ConsumeByteString() - return True - except ParseError: - return False - - def ConsumeString(self): - """Consumes a string value. - - Returns: - The string parsed. - - Raises: - ParseError: If a string value couldn't be consumed. - """ - the_bytes = self.ConsumeByteString() - try: - return str(the_bytes, 'utf-8') - except UnicodeDecodeError as e: - raise self._StringParseError(e) - - def ConsumeByteString(self): - """Consumes a byte array value. - - Returns: - The array parsed (as a string). - - Raises: - ParseError: If a byte array value couldn't be consumed. - """ - the_list = [self._ConsumeSingleByteString()] - while self.token and self.token[0] in _QUOTES: - the_list.append(self._ConsumeSingleByteString()) - return b''.join(the_list) - - def _ConsumeSingleByteString(self): - """Consume one token of a string literal. - - String literals (whether bytes or text) can come in multiple adjacent - tokens which are automatically concatenated, like in C or Python. This - method only consumes one token. - - Returns: - The token parsed. - Raises: - ParseError: When the wrong format data is found. - """ - text = self.token - if len(text) < 1 or text[0] not in _QUOTES: - raise self.ParseError('Expected string but found: %r' % (text,)) - - if len(text) < 2 or text[-1] != text[0]: - raise self.ParseError('String missing ending quote: %r' % (text,)) - - try: - result = text_encoding.CUnescape(text[1:-1]) - except ValueError as e: - raise self.ParseError(str(e)) - self.NextToken() - return result - - def ConsumeEnum(self, field): - try: - result = ParseEnum(field, self.token) - except ValueError as e: - raise self.ParseError(str(e)) - self.NextToken() - return result - - def ParseErrorPreviousToken(self, message): - """Creates and *returns* a ParseError for the previously read token. - - Args: - message: A message to set for the exception. - - Returns: - A ParseError instance. - """ - return ParseError(message, self._previous_line + 1, - self._previous_column + 1) - - def ParseError(self, message): - """Creates and *returns* a ParseError for the current token.""" - return ParseError('\'' + self._current_line + '\': ' + message, - self._line + 1, self._column + 1) - - def _StringParseError(self, e): - return self.ParseError('Couldn\'t parse string: ' + str(e)) - - def NextToken(self): - """Reads the next meaningful token.""" - self._previous_line = self._line - self._previous_column = self._column - - self._column += len(self.token) - self._SkipWhitespace() - - if not self._more_lines: - self.token = '' - return - - match = self._TOKEN.match(self._current_line, self._column) - if not match and not self._skip_comments: - match = self._COMMENT.match(self._current_line, self._column) - if match: - token = match.group(0) - self.token = token - else: - self.token = self._current_line[self._column] - -# Aliased so it can still be accessed by current visibility violators. -# TODO(dbarnett): Migrate violators to textformat_tokenizer. -_Tokenizer = Tokenizer # pylint: disable=invalid-name - - -def _ConsumeInt32(tokenizer): - """Consumes a signed 32bit integer number from tokenizer. - - Args: - tokenizer: A tokenizer used to parse the number. - - Returns: - The integer parsed. - - Raises: - ParseError: If a signed 32bit integer couldn't be consumed. - """ - return _ConsumeInteger(tokenizer, is_signed=True, is_long=False) - - -def _ConsumeUint32(tokenizer): - """Consumes an unsigned 32bit integer number from tokenizer. - - Args: - tokenizer: A tokenizer used to parse the number. - - Returns: - The integer parsed. - - Raises: - ParseError: If an unsigned 32bit integer couldn't be consumed. - """ - return _ConsumeInteger(tokenizer, is_signed=False, is_long=False) - - -def _TryConsumeInt64(tokenizer): - try: - _ConsumeInt64(tokenizer) - return True - except ParseError: - return False - - -def _ConsumeInt64(tokenizer): - """Consumes a signed 32bit integer number from tokenizer. - - Args: - tokenizer: A tokenizer used to parse the number. - - Returns: - The integer parsed. - - Raises: - ParseError: If a signed 32bit integer couldn't be consumed. - """ - return _ConsumeInteger(tokenizer, is_signed=True, is_long=True) - - -def _TryConsumeUint64(tokenizer): - try: - _ConsumeUint64(tokenizer) - return True - except ParseError: - return False - - -def _ConsumeUint64(tokenizer): - """Consumes an unsigned 64bit integer number from tokenizer. - - Args: - tokenizer: A tokenizer used to parse the number. - - Returns: - The integer parsed. - - Raises: - ParseError: If an unsigned 64bit integer couldn't be consumed. - """ - return _ConsumeInteger(tokenizer, is_signed=False, is_long=True) - - -def _ConsumeInteger(tokenizer, is_signed=False, is_long=False): - """Consumes an integer number from tokenizer. - - Args: - tokenizer: A tokenizer used to parse the number. - is_signed: True if a signed integer must be parsed. - is_long: True if a long integer must be parsed. - - Returns: - The integer parsed. - - Raises: - ParseError: If an integer with given characteristics couldn't be consumed. - """ - try: - result = ParseInteger(tokenizer.token, is_signed=is_signed, is_long=is_long) - except ValueError as e: - raise tokenizer.ParseError(str(e)) - tokenizer.NextToken() - return result - - -def ParseInteger(text, is_signed=False, is_long=False): - """Parses an integer. - - Args: - text: The text to parse. - is_signed: True if a signed integer must be parsed. - is_long: True if a long integer must be parsed. - - Returns: - The integer value. - - Raises: - ValueError: Thrown Iff the text is not a valid integer. - """ - # Do the actual parsing. Exception handling is propagated to caller. - result = _ParseAbstractInteger(text) - - # Check if the integer is sane. Exceptions handled by callers. - checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)] - checker.CheckValue(result) - return result - - -def _ParseAbstractInteger(text): - """Parses an integer without checking size/signedness. - - Args: - text: The text to parse. - - Returns: - The integer value. - - Raises: - ValueError: Thrown Iff the text is not a valid integer. - """ - # Do the actual parsing. Exception handling is propagated to caller. - orig_text = text - c_octal_match = re.match(r'(-?)0(\d+)$', text) - if c_octal_match: - # Python 3 no longer supports 0755 octal syntax without the 'o', so - # we always use the '0o' prefix for multi-digit numbers starting with 0. - text = c_octal_match.group(1) + '0o' + c_octal_match.group(2) - try: - return int(text, 0) - except ValueError: - raise ValueError('Couldn\'t parse integer: %s' % orig_text) - - -def ParseFloat(text): - """Parse a floating point number. - - Args: - text: Text to parse. - - Returns: - The number parsed. - - Raises: - ValueError: If a floating point number couldn't be parsed. - """ - try: - # Assume Python compatible syntax. - return float(text) - except ValueError: - # Check alternative spellings. - if _FLOAT_INFINITY.match(text): - if text[0] == '-': - return float('-inf') - else: - return float('inf') - elif _FLOAT_NAN.match(text): - return float('nan') - else: - # assume '1.0f' format - try: - return float(text.rstrip('f')) - except ValueError: - raise ValueError('Couldn\'t parse float: %s' % text) - - -def ParseBool(text): - """Parse a boolean value. - - Args: - text: Text to parse. - - Returns: - Boolean values parsed - - Raises: - ValueError: If text is not a valid boolean. - """ - if text in ('true', 't', '1', 'True'): - return True - elif text in ('false', 'f', '0', 'False'): - return False - else: - raise ValueError('Expected "true" or "false".') - - -def ParseEnum(field, value): - """Parse an enum value. - - The value can be specified by a number (the enum value), or by - a string literal (the enum name). - - Args: - field: Enum field descriptor. - value: String value. - - Returns: - Enum value number. - - Raises: - ValueError: If the enum value could not be parsed. - """ - enum_descriptor = field.enum_type - try: - number = int(value, 0) - except ValueError: - # Identifier. - enum_value = enum_descriptor.values_by_name.get(value, None) - if enum_value is None: - raise ValueError('Enum type "%s" has no value named %s.' % - (enum_descriptor.full_name, value)) - else: - # Numeric value. - if hasattr(field.file, 'syntax'): - # Attribute is checked for compatibility. - if field.file.syntax == 'proto3': - # Proto3 accept numeric unknown enums. - return number - enum_value = enum_descriptor.values_by_number.get(number, None) - if enum_value is None: - raise ValueError('Enum type "%s" has no value with number %d.' % - (enum_descriptor.full_name, number)) - return enum_value.number diff --git a/scripts/protobuf3/protobuf3/timestamp_pb2.py b/scripts/protobuf3/protobuf3/timestamp_pb2.py deleted file mode 100644 index 558d496..0000000 --- a/scripts/protobuf3/protobuf3/timestamp_pb2.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/timestamp.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1fgoogle/protobuf/timestamp.proto\x12\x0fgoogle.protobuf\"+\n\tTimestamp\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x85\x01\n\x13\x63om.google.protobufB\x0eTimestampProtoP\x01Z2google.golang.org/protobuf/types/known/timestamppb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.timestamp_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\016TimestampProtoP\001Z2google.golang.org/protobuf/types/known/timestamppb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' - _TIMESTAMP._serialized_start=52 - _TIMESTAMP._serialized_end=95 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/type_pb2.py b/scripts/protobuf3/protobuf3/type_pb2.py deleted file mode 100644 index 19903fb..0000000 --- a/scripts/protobuf3/protobuf3/type_pb2.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/type.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2 -from google.protobuf import source_context_pb2 as google_dot_protobuf_dot_source__context__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1agoogle/protobuf/type.proto\x12\x0fgoogle.protobuf\x1a\x19google/protobuf/any.proto\x1a$google/protobuf/source_context.proto\"\xd7\x01\n\x04Type\x12\x0c\n\x04name\x18\x01 \x01(\t\x12&\n\x06\x66ields\x18\x02 \x03(\x0b\x32\x16.google.protobuf.Field\x12\x0e\n\x06oneofs\x18\x03 \x03(\t\x12(\n\x07options\x18\x04 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x36\n\x0esource_context\x18\x05 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12\'\n\x06syntax\x18\x06 \x01(\x0e\x32\x17.google.protobuf.Syntax\"\xd5\x05\n\x05\x46ield\x12)\n\x04kind\x18\x01 \x01(\x0e\x32\x1b.google.protobuf.Field.Kind\x12\x37\n\x0b\x63\x61rdinality\x18\x02 \x01(\x0e\x32\".google.protobuf.Field.Cardinality\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x10\n\x08type_url\x18\x06 \x01(\t\x12\x13\n\x0boneof_index\x18\x07 \x01(\x05\x12\x0e\n\x06packed\x18\x08 \x01(\x08\x12(\n\x07options\x18\t \x03(\x0b\x32\x17.google.protobuf.Option\x12\x11\n\tjson_name\x18\n \x01(\t\x12\x15\n\rdefault_value\x18\x0b \x01(\t\"\xc8\x02\n\x04Kind\x12\x10\n\x0cTYPE_UNKNOWN\x10\x00\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"t\n\x0b\x43\x61rdinality\x12\x17\n\x13\x43\x41RDINALITY_UNKNOWN\x10\x00\x12\x18\n\x14\x43\x41RDINALITY_OPTIONAL\x10\x01\x12\x18\n\x14\x43\x41RDINALITY_REQUIRED\x10\x02\x12\x18\n\x14\x43\x41RDINALITY_REPEATED\x10\x03\"\xce\x01\n\x04\x45num\x12\x0c\n\x04name\x18\x01 \x01(\t\x12-\n\tenumvalue\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.EnumValue\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\x12\x36\n\x0esource_context\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.SourceContext\x12\'\n\x06syntax\x18\x05 \x01(\x0e\x32\x17.google.protobuf.Syntax\"S\n\tEnumValue\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12(\n\x07options\x18\x03 \x03(\x0b\x32\x17.google.protobuf.Option\";\n\x06Option\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.google.protobuf.Any*.\n\x06Syntax\x12\x11\n\rSYNTAX_PROTO2\x10\x00\x12\x11\n\rSYNTAX_PROTO3\x10\x01\x42{\n\x13\x63om.google.protobufB\tTypeProtoP\x01Z-google.golang.org/protobuf/types/known/typepb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.type_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\tTypeProtoP\001Z-google.golang.org/protobuf/types/known/typepb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' - _SYNTAX._serialized_start=1413 - _SYNTAX._serialized_end=1459 - _TYPE._serialized_start=113 - _TYPE._serialized_end=328 - _FIELD._serialized_start=331 - _FIELD._serialized_end=1056 - _FIELD_KIND._serialized_start=610 - _FIELD_KIND._serialized_end=938 - _FIELD_CARDINALITY._serialized_start=940 - _FIELD_CARDINALITY._serialized_end=1056 - _ENUM._serialized_start=1059 - _ENUM._serialized_end=1265 - _ENUMVALUE._serialized_start=1267 - _ENUMVALUE._serialized_end=1350 - _OPTION._serialized_start=1352 - _OPTION._serialized_end=1411 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/util/__init__.py b/scripts/protobuf3/protobuf3/util/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/protobuf3/protobuf3/util/json_format_pb2.py b/scripts/protobuf3/protobuf3/util/json_format_pb2.py deleted file mode 100644 index 66a5836..0000000 --- a/scripts/protobuf3/protobuf3/util/json_format_pb2.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/util/json_format.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n&google/protobuf/util/json_format.proto\x12\x11protobuf_unittest\"\x89\x01\n\x13TestFlagsAndStrings\x12\t\n\x01\x41\x18\x01 \x02(\x05\x12K\n\rrepeatedgroup\x18\x02 \x03(\n24.protobuf_unittest.TestFlagsAndStrings.RepeatedGroup\x1a\x1a\n\rRepeatedGroup\x12\t\n\x01\x66\x18\x03 \x02(\t\"!\n\x14TestBase64ByteArrays\x12\t\n\x01\x61\x18\x01 \x02(\x0c\"G\n\x12TestJavaScriptJSON\x12\t\n\x01\x61\x18\x01 \x01(\x05\x12\r\n\x05\x66inal\x18\x02 \x01(\x02\x12\n\n\x02in\x18\x03 \x01(\t\x12\x0b\n\x03Var\x18\x04 \x01(\t\"Q\n\x18TestJavaScriptOrderJSON1\x12\t\n\x01\x64\x18\x01 \x01(\x05\x12\t\n\x01\x63\x18\x02 \x01(\x05\x12\t\n\x01x\x18\x03 \x01(\x08\x12\t\n\x01\x62\x18\x04 \x01(\x05\x12\t\n\x01\x61\x18\x05 \x01(\x05\"\x89\x01\n\x18TestJavaScriptOrderJSON2\x12\t\n\x01\x64\x18\x01 \x01(\x05\x12\t\n\x01\x63\x18\x02 \x01(\x05\x12\t\n\x01x\x18\x03 \x01(\x08\x12\t\n\x01\x62\x18\x04 \x01(\x05\x12\t\n\x01\x61\x18\x05 \x01(\x05\x12\x36\n\x01z\x18\x06 \x03(\x0b\x32+.protobuf_unittest.TestJavaScriptOrderJSON1\"$\n\x0cTestLargeInt\x12\t\n\x01\x61\x18\x01 \x02(\x03\x12\t\n\x01\x62\x18\x02 \x02(\x04\"\xa0\x01\n\x0bTestNumbers\x12\x30\n\x01\x61\x18\x01 \x01(\x0e\x32%.protobuf_unittest.TestNumbers.MyType\x12\t\n\x01\x62\x18\x02 \x01(\x05\x12\t\n\x01\x63\x18\x03 \x01(\x02\x12\t\n\x01\x64\x18\x04 \x01(\x08\x12\t\n\x01\x65\x18\x05 \x01(\x01\x12\t\n\x01\x66\x18\x06 \x01(\r\"(\n\x06MyType\x12\x06\n\x02OK\x10\x00\x12\x0b\n\x07WARNING\x10\x01\x12\t\n\x05\x45RROR\x10\x02\"T\n\rTestCamelCase\x12\x14\n\x0cnormal_field\x18\x01 \x01(\t\x12\x15\n\rCAPITAL_FIELD\x18\x02 \x01(\x05\x12\x16\n\x0e\x43\x61melCaseField\x18\x03 \x01(\x05\"|\n\x0bTestBoolMap\x12=\n\x08\x62ool_map\x18\x01 \x03(\x0b\x32+.protobuf_unittest.TestBoolMap.BoolMapEntry\x1a.\n\x0c\x42oolMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"O\n\rTestRecursion\x12\r\n\x05value\x18\x01 \x01(\x05\x12/\n\x05\x63hild\x18\x02 \x01(\x0b\x32 .protobuf_unittest.TestRecursion\"\x86\x01\n\rTestStringMap\x12\x43\n\nstring_map\x18\x01 \x03(\x0b\x32/.protobuf_unittest.TestStringMap.StringMapEntry\x1a\x30\n\x0eStringMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xc4\x01\n\x14TestStringSerializer\x12\x15\n\rscalar_string\x18\x01 \x01(\t\x12\x17\n\x0frepeated_string\x18\x02 \x03(\t\x12J\n\nstring_map\x18\x03 \x03(\x0b\x32\x36.protobuf_unittest.TestStringSerializer.StringMapEntry\x1a\x30\n\x0eStringMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"$\n\x18TestMessageWithExtension*\x08\x08\x64\x10\x80\x80\x80\x80\x02\"z\n\rTestExtension\x12\r\n\x05value\x18\x01 \x01(\t2Z\n\x03\x65xt\x12+.protobuf_unittest.TestMessageWithExtension\x18\x64 \x01(\x0b\x32 .protobuf_unittest.TestExtension\"Q\n\x14TestDefaultEnumValue\x12\x39\n\nenum_value\x18\x01 \x01(\x0e\x32\x1c.protobuf_unittest.EnumValue:\x07\x44\x45\x46\x41ULT*2\n\tEnumValue\x12\x0c\n\x08PROTOCOL\x10\x00\x12\n\n\x06\x42UFFER\x10\x01\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x02') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.util.json_format_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - TestMessageWithExtension.RegisterExtension(_TESTEXTENSION.extensions_by_name['ext']) - - DESCRIPTOR._options = None - _TESTBOOLMAP_BOOLMAPENTRY._options = None - _TESTBOOLMAP_BOOLMAPENTRY._serialized_options = b'8\001' - _TESTSTRINGMAP_STRINGMAPENTRY._options = None - _TESTSTRINGMAP_STRINGMAPENTRY._serialized_options = b'8\001' - _TESTSTRINGSERIALIZER_STRINGMAPENTRY._options = None - _TESTSTRINGSERIALIZER_STRINGMAPENTRY._serialized_options = b'8\001' - _ENUMVALUE._serialized_start=1607 - _ENUMVALUE._serialized_end=1657 - _TESTFLAGSANDSTRINGS._serialized_start=62 - _TESTFLAGSANDSTRINGS._serialized_end=199 - _TESTFLAGSANDSTRINGS_REPEATEDGROUP._serialized_start=173 - _TESTFLAGSANDSTRINGS_REPEATEDGROUP._serialized_end=199 - _TESTBASE64BYTEARRAYS._serialized_start=201 - _TESTBASE64BYTEARRAYS._serialized_end=234 - _TESTJAVASCRIPTJSON._serialized_start=236 - _TESTJAVASCRIPTJSON._serialized_end=307 - _TESTJAVASCRIPTORDERJSON1._serialized_start=309 - _TESTJAVASCRIPTORDERJSON1._serialized_end=390 - _TESTJAVASCRIPTORDERJSON2._serialized_start=393 - _TESTJAVASCRIPTORDERJSON2._serialized_end=530 - _TESTLARGEINT._serialized_start=532 - _TESTLARGEINT._serialized_end=568 - _TESTNUMBERS._serialized_start=571 - _TESTNUMBERS._serialized_end=731 - _TESTNUMBERS_MYTYPE._serialized_start=691 - _TESTNUMBERS_MYTYPE._serialized_end=731 - _TESTCAMELCASE._serialized_start=733 - _TESTCAMELCASE._serialized_end=817 - _TESTBOOLMAP._serialized_start=819 - _TESTBOOLMAP._serialized_end=943 - _TESTBOOLMAP_BOOLMAPENTRY._serialized_start=897 - _TESTBOOLMAP_BOOLMAPENTRY._serialized_end=943 - _TESTRECURSION._serialized_start=945 - _TESTRECURSION._serialized_end=1024 - _TESTSTRINGMAP._serialized_start=1027 - _TESTSTRINGMAP._serialized_end=1161 - _TESTSTRINGMAP_STRINGMAPENTRY._serialized_start=1113 - _TESTSTRINGMAP_STRINGMAPENTRY._serialized_end=1161 - _TESTSTRINGSERIALIZER._serialized_start=1164 - _TESTSTRINGSERIALIZER._serialized_end=1360 - _TESTSTRINGSERIALIZER_STRINGMAPENTRY._serialized_start=1113 - _TESTSTRINGSERIALIZER_STRINGMAPENTRY._serialized_end=1161 - _TESTMESSAGEWITHEXTENSION._serialized_start=1362 - _TESTMESSAGEWITHEXTENSION._serialized_end=1398 - _TESTEXTENSION._serialized_start=1400 - _TESTEXTENSION._serialized_end=1522 - _TESTDEFAULTENUMVALUE._serialized_start=1524 - _TESTDEFAULTENUMVALUE._serialized_end=1605 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/util/json_format_proto3_pb2.py b/scripts/protobuf3/protobuf3/util/json_format_proto3_pb2.py deleted file mode 100644 index 5498dea..0000000 --- a/scripts/protobuf3/protobuf3/util/json_format_proto3_pb2.py +++ /dev/null @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/util/json_format_proto3.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - -from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2 -from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2 -from google.protobuf import field_mask_pb2 as google_dot_protobuf_dot_field__mask__pb2 -from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 -from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 -from google.protobuf import wrappers_pb2 as google_dot_protobuf_dot_wrappers__pb2 -from google.protobuf import unittest_pb2 as google_dot_protobuf_dot_unittest__pb2 - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n-google/protobuf/util/json_format_proto3.proto\x12\x06proto3\x1a\x19google/protobuf/any.proto\x1a\x1egoogle/protobuf/duration.proto\x1a google/protobuf/field_mask.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1egoogle/protobuf/unittest.proto\"\x1c\n\x0bMessageType\x12\r\n\x05value\x18\x01 \x01(\x05\"\x94\x05\n\x0bTestMessage\x12\x12\n\nbool_value\x18\x01 \x01(\x08\x12\x13\n\x0bint32_value\x18\x02 \x01(\x05\x12\x13\n\x0bint64_value\x18\x03 \x01(\x03\x12\x14\n\x0cuint32_value\x18\x04 \x01(\r\x12\x14\n\x0cuint64_value\x18\x05 \x01(\x04\x12\x13\n\x0b\x66loat_value\x18\x06 \x01(\x02\x12\x14\n\x0c\x64ouble_value\x18\x07 \x01(\x01\x12\x14\n\x0cstring_value\x18\x08 \x01(\t\x12\x13\n\x0b\x62ytes_value\x18\t \x01(\x0c\x12$\n\nenum_value\x18\n \x01(\x0e\x32\x10.proto3.EnumType\x12*\n\rmessage_value\x18\x0b \x01(\x0b\x32\x13.proto3.MessageType\x12\x1b\n\x13repeated_bool_value\x18\x15 \x03(\x08\x12\x1c\n\x14repeated_int32_value\x18\x16 \x03(\x05\x12\x1c\n\x14repeated_int64_value\x18\x17 \x03(\x03\x12\x1d\n\x15repeated_uint32_value\x18\x18 \x03(\r\x12\x1d\n\x15repeated_uint64_value\x18\x19 \x03(\x04\x12\x1c\n\x14repeated_float_value\x18\x1a \x03(\x02\x12\x1d\n\x15repeated_double_value\x18\x1b \x03(\x01\x12\x1d\n\x15repeated_string_value\x18\x1c \x03(\t\x12\x1c\n\x14repeated_bytes_value\x18\x1d \x03(\x0c\x12-\n\x13repeated_enum_value\x18\x1e \x03(\x0e\x32\x10.proto3.EnumType\x12\x33\n\x16repeated_message_value\x18\x1f \x03(\x0b\x32\x13.proto3.MessageType\"\x8c\x02\n\tTestOneof\x12\x1b\n\x11oneof_int32_value\x18\x01 \x01(\x05H\x00\x12\x1c\n\x12oneof_string_value\x18\x02 \x01(\tH\x00\x12\x1b\n\x11oneof_bytes_value\x18\x03 \x01(\x0cH\x00\x12,\n\x10oneof_enum_value\x18\x04 \x01(\x0e\x32\x10.proto3.EnumTypeH\x00\x12\x32\n\x13oneof_message_value\x18\x05 \x01(\x0b\x32\x13.proto3.MessageTypeH\x00\x12\x36\n\x10oneof_null_value\x18\x06 \x01(\x0e\x32\x1a.google.protobuf.NullValueH\x00\x42\r\n\x0boneof_value\"\xe1\x04\n\x07TestMap\x12.\n\x08\x62ool_map\x18\x01 \x03(\x0b\x32\x1c.proto3.TestMap.BoolMapEntry\x12\x30\n\tint32_map\x18\x02 \x03(\x0b\x32\x1d.proto3.TestMap.Int32MapEntry\x12\x30\n\tint64_map\x18\x03 \x03(\x0b\x32\x1d.proto3.TestMap.Int64MapEntry\x12\x32\n\nuint32_map\x18\x04 \x03(\x0b\x32\x1e.proto3.TestMap.Uint32MapEntry\x12\x32\n\nuint64_map\x18\x05 \x03(\x0b\x32\x1e.proto3.TestMap.Uint64MapEntry\x12\x32\n\nstring_map\x18\x06 \x03(\x0b\x32\x1e.proto3.TestMap.StringMapEntry\x1a.\n\x0c\x42oolMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a/\n\rInt32MapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a/\n\rInt64MapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x03\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x30\n\x0eUint32MapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x30\n\x0eUint64MapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x30\n\x0eStringMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"\x85\x06\n\rTestNestedMap\x12\x34\n\x08\x62ool_map\x18\x01 \x03(\x0b\x32\".proto3.TestNestedMap.BoolMapEntry\x12\x36\n\tint32_map\x18\x02 \x03(\x0b\x32#.proto3.TestNestedMap.Int32MapEntry\x12\x36\n\tint64_map\x18\x03 \x03(\x0b\x32#.proto3.TestNestedMap.Int64MapEntry\x12\x38\n\nuint32_map\x18\x04 \x03(\x0b\x32$.proto3.TestNestedMap.Uint32MapEntry\x12\x38\n\nuint64_map\x18\x05 \x03(\x0b\x32$.proto3.TestNestedMap.Uint64MapEntry\x12\x38\n\nstring_map\x18\x06 \x03(\x0b\x32$.proto3.TestNestedMap.StringMapEntry\x12\x32\n\x07map_map\x18\x07 \x03(\x0b\x32!.proto3.TestNestedMap.MapMapEntry\x1a.\n\x0c\x42oolMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a/\n\rInt32MapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a/\n\rInt64MapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x03\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x30\n\x0eUint32MapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x30\n\x0eUint64MapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x04\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x30\n\x0eStringMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x44\n\x0bMapMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.proto3.TestNestedMap:\x02\x38\x01\"{\n\rTestStringMap\x12\x38\n\nstring_map\x18\x01 \x03(\x0b\x32$.proto3.TestStringMap.StringMapEntry\x1a\x30\n\x0eStringMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xee\x07\n\x0bTestWrapper\x12.\n\nbool_value\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x30\n\x0bint32_value\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.Int32Value\x12\x30\n\x0bint64_value\x18\x03 \x01(\x0b\x32\x1b.google.protobuf.Int64Value\x12\x32\n\x0cuint32_value\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x32\n\x0cuint64_value\x18\x05 \x01(\x0b\x32\x1c.google.protobuf.UInt64Value\x12\x30\n\x0b\x66loat_value\x18\x06 \x01(\x0b\x32\x1b.google.protobuf.FloatValue\x12\x32\n\x0c\x64ouble_value\x18\x07 \x01(\x0b\x32\x1c.google.protobuf.DoubleValue\x12\x32\n\x0cstring_value\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.StringValue\x12\x30\n\x0b\x62ytes_value\x18\t \x01(\x0b\x32\x1b.google.protobuf.BytesValue\x12\x37\n\x13repeated_bool_value\x18\x0b \x03(\x0b\x32\x1a.google.protobuf.BoolValue\x12\x39\n\x14repeated_int32_value\x18\x0c \x03(\x0b\x32\x1b.google.protobuf.Int32Value\x12\x39\n\x14repeated_int64_value\x18\r \x03(\x0b\x32\x1b.google.protobuf.Int64Value\x12;\n\x15repeated_uint32_value\x18\x0e \x03(\x0b\x32\x1c.google.protobuf.UInt32Value\x12;\n\x15repeated_uint64_value\x18\x0f \x03(\x0b\x32\x1c.google.protobuf.UInt64Value\x12\x39\n\x14repeated_float_value\x18\x10 \x03(\x0b\x32\x1b.google.protobuf.FloatValue\x12;\n\x15repeated_double_value\x18\x11 \x03(\x0b\x32\x1c.google.protobuf.DoubleValue\x12;\n\x15repeated_string_value\x18\x12 \x03(\x0b\x32\x1c.google.protobuf.StringValue\x12\x39\n\x14repeated_bytes_value\x18\x13 \x03(\x0b\x32\x1b.google.protobuf.BytesValue\"n\n\rTestTimestamp\x12)\n\x05value\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x32\n\x0erepeated_value\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.Timestamp\"k\n\x0cTestDuration\x12(\n\x05value\x18\x01 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x31\n\x0erepeated_value\x18\x02 \x03(\x0b\x32\x19.google.protobuf.Duration\":\n\rTestFieldMask\x12)\n\x05value\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.FieldMask\"e\n\nTestStruct\x12&\n\x05value\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12/\n\x0erepeated_value\x18\x02 \x03(\x0b\x32\x17.google.protobuf.Struct\"\\\n\x07TestAny\x12#\n\x05value\x18\x01 \x01(\x0b\x32\x14.google.protobuf.Any\x12,\n\x0erepeated_value\x18\x02 \x03(\x0b\x32\x14.google.protobuf.Any\"b\n\tTestValue\x12%\n\x05value\x18\x01 \x01(\x0b\x32\x16.google.protobuf.Value\x12.\n\x0erepeated_value\x18\x02 \x03(\x0b\x32\x16.google.protobuf.Value\"n\n\rTestListValue\x12)\n\x05value\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.ListValue\x12\x32\n\x0erepeated_value\x18\x02 \x03(\x0b\x32\x1a.google.protobuf.ListValue\"\x89\x01\n\rTestBoolValue\x12\x12\n\nbool_value\x18\x01 \x01(\x08\x12\x34\n\x08\x62ool_map\x18\x02 \x03(\x0b\x32\".proto3.TestBoolValue.BoolMapEntry\x1a.\n\x0c\x42oolMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"+\n\x12TestCustomJsonName\x12\x15\n\x05value\x18\x01 \x01(\x05R\x06@value\"J\n\x0eTestExtensions\x12\x38\n\nextensions\x18\x01 \x01(\x0b\x32$.protobuf_unittest.TestAllExtensions\"\x84\x01\n\rTestEnumValue\x12%\n\x0b\x65num_value1\x18\x01 \x01(\x0e\x32\x10.proto3.EnumType\x12%\n\x0b\x65num_value2\x18\x02 \x01(\x0e\x32\x10.proto3.EnumType\x12%\n\x0b\x65num_value3\x18\x03 \x01(\x0e\x32\x10.proto3.EnumType*\x1c\n\x08\x45numType\x12\x07\n\x03\x46OO\x10\x00\x12\x07\n\x03\x42\x41R\x10\x01\x42,\n\x18\x63om.google.protobuf.utilB\x10JsonFormatProto3b\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.util.json_format_proto3_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\030com.google.protobuf.utilB\020JsonFormatProto3' - _TESTMAP_BOOLMAPENTRY._options = None - _TESTMAP_BOOLMAPENTRY._serialized_options = b'8\001' - _TESTMAP_INT32MAPENTRY._options = None - _TESTMAP_INT32MAPENTRY._serialized_options = b'8\001' - _TESTMAP_INT64MAPENTRY._options = None - _TESTMAP_INT64MAPENTRY._serialized_options = b'8\001' - _TESTMAP_UINT32MAPENTRY._options = None - _TESTMAP_UINT32MAPENTRY._serialized_options = b'8\001' - _TESTMAP_UINT64MAPENTRY._options = None - _TESTMAP_UINT64MAPENTRY._serialized_options = b'8\001' - _TESTMAP_STRINGMAPENTRY._options = None - _TESTMAP_STRINGMAPENTRY._serialized_options = b'8\001' - _TESTNESTEDMAP_BOOLMAPENTRY._options = None - _TESTNESTEDMAP_BOOLMAPENTRY._serialized_options = b'8\001' - _TESTNESTEDMAP_INT32MAPENTRY._options = None - _TESTNESTEDMAP_INT32MAPENTRY._serialized_options = b'8\001' - _TESTNESTEDMAP_INT64MAPENTRY._options = None - _TESTNESTEDMAP_INT64MAPENTRY._serialized_options = b'8\001' - _TESTNESTEDMAP_UINT32MAPENTRY._options = None - _TESTNESTEDMAP_UINT32MAPENTRY._serialized_options = b'8\001' - _TESTNESTEDMAP_UINT64MAPENTRY._options = None - _TESTNESTEDMAP_UINT64MAPENTRY._serialized_options = b'8\001' - _TESTNESTEDMAP_STRINGMAPENTRY._options = None - _TESTNESTEDMAP_STRINGMAPENTRY._serialized_options = b'8\001' - _TESTNESTEDMAP_MAPMAPENTRY._options = None - _TESTNESTEDMAP_MAPMAPENTRY._serialized_options = b'8\001' - _TESTSTRINGMAP_STRINGMAPENTRY._options = None - _TESTSTRINGMAP_STRINGMAPENTRY._serialized_options = b'8\001' - _TESTBOOLVALUE_BOOLMAPENTRY._options = None - _TESTBOOLVALUE_BOOLMAPENTRY._serialized_options = b'8\001' - _ENUMTYPE._serialized_start=4849 - _ENUMTYPE._serialized_end=4877 - _MESSAGETYPE._serialized_start=277 - _MESSAGETYPE._serialized_end=305 - _TESTMESSAGE._serialized_start=308 - _TESTMESSAGE._serialized_end=968 - _TESTONEOF._serialized_start=971 - _TESTONEOF._serialized_end=1239 - _TESTMAP._serialized_start=1242 - _TESTMAP._serialized_end=1851 - _TESTMAP_BOOLMAPENTRY._serialized_start=1557 - _TESTMAP_BOOLMAPENTRY._serialized_end=1603 - _TESTMAP_INT32MAPENTRY._serialized_start=1605 - _TESTMAP_INT32MAPENTRY._serialized_end=1652 - _TESTMAP_INT64MAPENTRY._serialized_start=1654 - _TESTMAP_INT64MAPENTRY._serialized_end=1701 - _TESTMAP_UINT32MAPENTRY._serialized_start=1703 - _TESTMAP_UINT32MAPENTRY._serialized_end=1751 - _TESTMAP_UINT64MAPENTRY._serialized_start=1753 - _TESTMAP_UINT64MAPENTRY._serialized_end=1801 - _TESTMAP_STRINGMAPENTRY._serialized_start=1803 - _TESTMAP_STRINGMAPENTRY._serialized_end=1851 - _TESTNESTEDMAP._serialized_start=1854 - _TESTNESTEDMAP._serialized_end=2627 - _TESTNESTEDMAP_BOOLMAPENTRY._serialized_start=1557 - _TESTNESTEDMAP_BOOLMAPENTRY._serialized_end=1603 - _TESTNESTEDMAP_INT32MAPENTRY._serialized_start=1605 - _TESTNESTEDMAP_INT32MAPENTRY._serialized_end=1652 - _TESTNESTEDMAP_INT64MAPENTRY._serialized_start=1654 - _TESTNESTEDMAP_INT64MAPENTRY._serialized_end=1701 - _TESTNESTEDMAP_UINT32MAPENTRY._serialized_start=1703 - _TESTNESTEDMAP_UINT32MAPENTRY._serialized_end=1751 - _TESTNESTEDMAP_UINT64MAPENTRY._serialized_start=1753 - _TESTNESTEDMAP_UINT64MAPENTRY._serialized_end=1801 - _TESTNESTEDMAP_STRINGMAPENTRY._serialized_start=1803 - _TESTNESTEDMAP_STRINGMAPENTRY._serialized_end=1851 - _TESTNESTEDMAP_MAPMAPENTRY._serialized_start=2559 - _TESTNESTEDMAP_MAPMAPENTRY._serialized_end=2627 - _TESTSTRINGMAP._serialized_start=2629 - _TESTSTRINGMAP._serialized_end=2752 - _TESTSTRINGMAP_STRINGMAPENTRY._serialized_start=2704 - _TESTSTRINGMAP_STRINGMAPENTRY._serialized_end=2752 - _TESTWRAPPER._serialized_start=2755 - _TESTWRAPPER._serialized_end=3761 - _TESTTIMESTAMP._serialized_start=3763 - _TESTTIMESTAMP._serialized_end=3873 - _TESTDURATION._serialized_start=3875 - _TESTDURATION._serialized_end=3982 - _TESTFIELDMASK._serialized_start=3984 - _TESTFIELDMASK._serialized_end=4042 - _TESTSTRUCT._serialized_start=4044 - _TESTSTRUCT._serialized_end=4145 - _TESTANY._serialized_start=4147 - _TESTANY._serialized_end=4239 - _TESTVALUE._serialized_start=4241 - _TESTVALUE._serialized_end=4339 - _TESTLISTVALUE._serialized_start=4341 - _TESTLISTVALUE._serialized_end=4451 - _TESTBOOLVALUE._serialized_start=4454 - _TESTBOOLVALUE._serialized_end=4591 - _TESTBOOLVALUE_BOOLMAPENTRY._serialized_start=1557 - _TESTBOOLVALUE_BOOLMAPENTRY._serialized_end=1603 - _TESTCUSTOMJSONNAME._serialized_start=4593 - _TESTCUSTOMJSONNAME._serialized_end=4636 - _TESTEXTENSIONS._serialized_start=4638 - _TESTEXTENSIONS._serialized_end=4712 - _TESTENUMVALUE._serialized_start=4715 - _TESTENUMVALUE._serialized_end=4847 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/protobuf3/wrappers_pb2.py b/scripts/protobuf3/protobuf3/wrappers_pb2.py deleted file mode 100644 index e49eb4c..0000000 --- a/scripts/protobuf3/protobuf3/wrappers_pb2.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: google/protobuf/wrappers.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1egoogle/protobuf/wrappers.proto\x12\x0fgoogle.protobuf\"\x1c\n\x0b\x44oubleValue\x12\r\n\x05value\x18\x01 \x01(\x01\"\x1b\n\nFloatValue\x12\r\n\x05value\x18\x01 \x01(\x02\"\x1b\n\nInt64Value\x12\r\n\x05value\x18\x01 \x01(\x03\"\x1c\n\x0bUInt64Value\x12\r\n\x05value\x18\x01 \x01(\x04\"\x1b\n\nInt32Value\x12\r\n\x05value\x18\x01 \x01(\x05\"\x1c\n\x0bUInt32Value\x12\r\n\x05value\x18\x01 \x01(\r\"\x1a\n\tBoolValue\x12\r\n\x05value\x18\x01 \x01(\x08\"\x1c\n\x0bStringValue\x12\r\n\x05value\x18\x01 \x01(\t\"\x1b\n\nBytesValue\x12\r\n\x05value\x18\x01 \x01(\x0c\x42\x83\x01\n\x13\x63om.google.protobufB\rWrappersProtoP\x01Z1google.golang.org/protobuf/types/known/wrapperspb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.wrappers_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\023com.google.protobufB\rWrappersProtoP\001Z1google.golang.org/protobuf/types/known/wrapperspb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes' - _DOUBLEVALUE._serialized_start=51 - _DOUBLEVALUE._serialized_end=79 - _FLOATVALUE._serialized_start=81 - _FLOATVALUE._serialized_end=108 - _INT64VALUE._serialized_start=110 - _INT64VALUE._serialized_end=137 - _UINT64VALUE._serialized_start=139 - _UINT64VALUE._serialized_end=167 - _INT32VALUE._serialized_start=169 - _INT32VALUE._serialized_end=196 - _UINT32VALUE._serialized_start=198 - _UINT32VALUE._serialized_end=226 - _BOOLVALUE._serialized_start=228 - _BOOLVALUE._serialized_end=254 - _STRINGVALUE._serialized_start=256 - _STRINGVALUE._serialized_end=284 - _BYTESVALUE._serialized_start=286 - _BYTESVALUE._serialized_end=313 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/protobuf3/pyproject.toml b/scripts/protobuf3/pyproject.toml deleted file mode 100644 index 100fbc9..0000000 --- a/scripts/protobuf3/pyproject.toml +++ /dev/null @@ -1,19 +0,0 @@ -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - -[tool.poetry] -name = "protobuf3" -version = "3.20.2" -description = "protobuf3" -license = "CC BY-NC-ND 4.0" -authors = ["google"] -repository = "https://github.com/protocolbuffers/protobuf/" - - -[tool.poetry.urls] -"Issues" = "https://github.com/protocolbuffers/protobuf//issues" - -[tool.poetry.dependencies] -python = ">=3.7,<4.0" -requests = "^2.32.3" diff --git a/scripts/pyplayready/README.md b/scripts/pyplayready/README.md deleted file mode 100644 index 963f8ef..0000000 --- a/scripts/pyplayready/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# pyplayready -All of this is already public. 100% of this code has been derived from the mspr_toolkit. - -## Installation -```shell -pip install pyplayready -``` - -Run `pyplayready --help` to view available cli functions - -## Devices -Run the command below to create a Playready Device (.prd) from a `bgroupcert.dat` and `zgpriv.dat`: -```shell -pyplayready create-device -c bgroupcert.dat -k zgpriv.dat -``` - -Test a playready device: -```shell -pyplayready test DEVICE.prd -``` - -> [!IMPORTANT] -> There currently isn't a proper method of extracting Group Certificates/Keys. They can be found inside older Samsung phones/Smart TVs, Windows DLLs and set-top-boxes in encrypted form. - -Export a provisioned device to its raw .dat files -```shell -pyplayready export-device DEVICE.prd -``` - -## Usage -An example code snippet: - -```python -from pyplayready.cdm import Cdm -from pyplayready.device import Device -from pyplayready.system.pssh import PSSH - -import requests - -device = Device.load("C:/Path/To/A/Device.prd") -cdm = Cdm.from_device(device) -session_id = cdm.open() - -pssh = PSSH( - "AAADfHBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAA1xcAwAAAQABAFIDPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AH" - "QAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABh" - "AHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUg" - "BPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQA" - "UgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgA0AFIAcABsAGIAKwBUAGIATgBFAFMAOAB0AE" - "cAawBOAEYAVwBUAEUASABBAD0APQA8AC8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEsATABqADMAUQB6AFEAUAAvAE4AQQA9ADwALwBD" - "AEgARQBDAEsAUwBVAE0APgA8AEwAQQBfAFUAUgBMAD4AaAB0AHQAcABzADoALwAvAHAAcgBvAGYAZgBpAGMAaQBhAGwAcwBpAHQAZQAuAGsAZQ" - "B5AGQAZQBsAGkAdgBlAHIAeQAuAG0AZQBkAGkAYQBzAGUAcgB2AGkAYwBlAHMALgB3AGkAbgBkAG8AdwBzAC4AbgBlAHQALwBQAGwAYQB5AFIA" - "ZQBhAGQAeQAvADwALwBMAEEAXwBVAFIATAA+ADwAQwBVAFMAVABPAE0AQQBUAFQAUgBJAEIAVQBUAEUAUwA+ADwASQBJAFMAXwBEAFIATQBfAF" - "YARQBSAFMASQBPAE4APgA4AC4AMQAuADIAMwAwADQALgAzADEAPAAvAEkASQBTAF8ARABSAE0AXwBWAEUAUgBTAEkATwBOAD4APAAvAEMAVQBT" - "AFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==" -) - -wrm_headers = pssh.get_wrm_headers() -request = cdm.get_license_challenge(session_id, wrm_headers[0]) - -response = requests.post( - url="https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:2000)", - headers={ - 'Content-Type': 'text/xml; charset=UTF-8', - }, - data=request, -) - -cdm.parse_license(session_id, response.text) - -for key in cdm.get_keys(session_id): - print(f"{key.key_id.hex}:{key.key.hex()}") - -cdm.close(session_id) -``` - -## Disclaimer - -1. This project requires a valid Microsoft Certificate and Group Key, which are not provided by this project. -2. Public test provisions are available and provided by Microsoft to use for testing projects such as this one. -3. This project does not condone piracy or any action against the terms of the DRM systems. -4. All efforts in this project have been the result of Reverse-Engineering, Publicly available research, and Trial & Error. -5. Do not use this program to decrypt or access any content for which you do not have the legal rights or explicit permission. -6. Unauthorized decryption or distribution of copyrighted materials is a violation of applicable laws and intellectual property rights. -7. This tool must not be used for any illegal activities, including but not limited to piracy, circumventing digital rights management (DRM), or unauthorized access to protected content. -8. The developers, contributors, and maintainers of this program are not responsible for any misuse or illegal activities performed using this software. -9. By using this program, you agree to comply with all applicable laws and regulations governing digital rights and copyright protections. - -## Credits -+ [mspr_toolkit](https://security-explorations.com/materials/mspr_toolkit.zip) diff --git a/scripts/pyplayready/pyplayready/__init__.py b/scripts/pyplayready/pyplayready/__init__.py deleted file mode 100644 index 0ff5604..0000000 --- a/scripts/pyplayready/pyplayready/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from pyplayready.cdm import * -from pyplayready.crypto.ecc_key import * -from pyplayready.crypto.elgamal import * -from pyplayready.device import * -from pyplayready.license.key import * -from pyplayready.license.xml_key import * -from pyplayready.license.xmrlicense import * -from pyplayready.remote.remotecdm import * -from pyplayready.system.bcert import * -from pyplayready.system.pssh import * -from pyplayready.system.session import * - - -__version__ = "0.5.0" diff --git a/scripts/pyplayready/pyplayready/crypto/__init__.py b/scripts/pyplayready/pyplayready/crypto/__init__.py deleted file mode 100644 index 4e339eb..0000000 --- a/scripts/pyplayready/pyplayready/crypto/__init__.py +++ /dev/null @@ -1,96 +0,0 @@ -from typing import Union, Tuple - -from Crypto.Hash import SHA256 -from Crypto.Hash.SHA256 import SHA256Hash -from Crypto.PublicKey.ECC import EccKey -from Crypto.Signature import DSS -from ecpy.curves import Point, Curve - -from pyplayready.crypto.elgamal import ElGamal -from pyplayready.crypto.ecc_key import ECCKey - - -class Crypto: - def __init__(self, curve: str = "secp256r1"): - self.curve = Curve.get_curve(curve) - self.elgamal = ElGamal(self.curve) - - def ecc256_encrypt(self, public_key: Union[ECCKey, Point], plaintext: Union[Point, bytes]) -> bytes: - if isinstance(public_key, ECCKey): - public_key = public_key.get_point(self.curve) - if not isinstance(public_key, Point): - raise ValueError(f"Expecting ECCKey or Point input, got {public_key!r}") - - if isinstance(plaintext, bytes): - plaintext = Point( - x=int.from_bytes(plaintext[:32], 'big'), - y=int.from_bytes(plaintext[32:64], 'big'), - curve=self.curve - ) - if not isinstance(plaintext, Point): - raise ValueError(f"Expecting Point or Bytes input, got {plaintext!r}") - - point1, point2 = self.elgamal.encrypt( - message_point=plaintext, - public_key=public_key - ) - return b''.join([ - self.elgamal.to_bytes(point1.x), - self.elgamal.to_bytes(point1.y), - self.elgamal.to_bytes(point2.x), - self.elgamal.to_bytes(point2.y) - ]) - - def ecc256_decrypt(self, private_key: ECCKey, ciphertext: Union[Tuple[Point, Point], bytes]) -> bytes: - if isinstance(ciphertext, bytes): - ciphertext = ( - Point( - x=int.from_bytes(ciphertext[:32], 'big'), - y=int.from_bytes(ciphertext[32:64], 'big'), - curve=self.curve - ), - Point( - x=int.from_bytes(ciphertext[64:96], 'big'), - y=int.from_bytes(ciphertext[96:128], 'big'), - curve=self.curve - ) - ) - if not isinstance(ciphertext, Tuple): - raise ValueError(f"Expecting Tuple[Point, Point] or Bytes input, got {ciphertext!r}") - - decrypted = self.elgamal.decrypt(ciphertext, int(private_key.key.d)) - return self.elgamal.to_bytes(decrypted.x) - - @staticmethod - def ecc256_sign(private_key: Union[ECCKey, EccKey], data: Union[SHA256Hash, bytes]) -> bytes: - if isinstance(private_key, ECCKey): - private_key = private_key.key - if not isinstance(private_key, EccKey): - raise ValueError(f"Expecting ECCKey or EccKey input, got {private_key!r}") - - if isinstance(data, bytes): - data = SHA256.new(data) - if not isinstance(data, SHA256Hash): - raise ValueError(f"Expecting SHA256Hash or Bytes input, got {data!r}") - - signer = DSS.new(private_key, 'fips-186-3') - return signer.sign(data) - - @staticmethod - def ecc256_verify(public_key: Union[ECCKey, EccKey], data: Union[SHA256Hash, bytes], signature: bytes) -> bool: - if isinstance(public_key, ECCKey): - public_key = public_key.key - if not isinstance(public_key, EccKey): - raise ValueError(f"Expecting ECCKey or EccKey input, got {public_key!r}") - - if isinstance(data, bytes): - data = SHA256.new(data) - if not isinstance(data, SHA256Hash): - raise ValueError(f"Expecting SHA256Hash or Bytes input, got {data!r}") - - verifier = DSS.new(public_key, 'fips-186-3') - try: - verifier.verify(data, signature) - return True - except ValueError: - return False diff --git a/scripts/pyplayready/pyplayready/device/structs.py b/scripts/pyplayready/pyplayready/device/structs.py deleted file mode 100644 index 7a7bda2..0000000 --- a/scripts/pyplayready/pyplayready/device/structs.py +++ /dev/null @@ -1,41 +0,0 @@ -from construct import Struct, Const, Int8ub, Bytes, this, Int32ub, Switch, Embedded - - -class DeviceStructs: - magic = Const(b"PRD") - - # was never in production - v1 = Struct( - "group_key_length" / Int32ub, - "group_key" / Bytes(this.group_key_length), - "group_certificate_length" / Int32ub, - "group_certificate" / Bytes(this.group_certificate_length) - ) - - v2 = Struct( - "group_certificate_length" / Int32ub, - "group_certificate" / Bytes(this.group_certificate_length), - "encryption_key" / Bytes(96), - "signing_key" / Bytes(96), - ) - - v3 = Struct( - "group_key" / Bytes(96), - "encryption_key" / Bytes(96), - "signing_key" / Bytes(96), - "group_certificate_length" / Int32ub, - "group_certificate" / Bytes(this.group_certificate_length), - ) - - prd = Struct( - "signature" / magic, - "version" / Int8ub, - Embedded(Switch( - lambda ctx: ctx.version, - { - 1: v1, - 2: v2, - 3: v3 - } - )) - ) diff --git a/scripts/pyplayready/pyproject.toml b/scripts/pyplayready/pyproject.toml deleted file mode 100644 index 990c7ee..0000000 --- a/scripts/pyplayready/pyproject.toml +++ /dev/null @@ -1,44 +0,0 @@ -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - -[tool.poetry] -name = "pyplayready" -version = "0.5.0" -description = "pyplayready CDM (Content Decryption Module) implementation in Python." -license = "CC BY-NC-ND 4.0" -authors = ["DevLARLEY, Erevoc", "DevataDev"] -readme = "README.md" -repository = "https://github.com/ready-dl/pyplayready" -keywords = ["python", "drm", "playready", "microsoft"] -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Intended Audience :: End Users/Desktop", - "Natural Language :: English", - "Operating System :: OS Independent", - "Topic :: Multimedia :: Video", - "Topic :: Security :: Cryptography", - "Topic :: Software Development :: Libraries :: Python Modules" -] -include = [ - { path = "README.md", format = "sdist" }, - { path = "LICENSE", format = "sdist" }, -] - -[tool.poetry.urls] -"Issues" = "https://github.com/ready-dl/pyplayready/issues" - -[tool.poetry.dependencies] -python = ">=3.8,<4.0" -requests = "^2.32.3" -pycryptodome = "^3.21.0" -construct = "^2.8.8" -ECPy = "^1.2.5" -click = "^8.1.7" -xmltodict = "^0.14.2" -PyYAML = "^6.0.1" -aiohttp = {version = "^3.9.1", optional = true} - -[tool.poetry.scripts] -pyplayready = "pyplayready.main:main" diff --git a/scripts/pywidevine/README.md b/scripts/pywidevine/README.md deleted file mode 100644 index db05668..0000000 --- a/scripts/pywidevine/README.md +++ /dev/null @@ -1,166 +0,0 @@ -

- pywidevine -
- Python Widevine CDM implementation -

- -

- - Build status - - - Python version - - - DeepSource - -

-

- - Linter: Ruff - - - Dependency management: Poetry - -

- -## Features - -- 🚀 Seamless Installation via [pip](#installation) -- 🛡️ Robust Security with message signature verification -- 🙈 Privacy Mode with Service Certificates -- 🌐 Servable CDM API Server and Client with Authentication -- 📦 Custom provision serialization format (WVD v2) -- 🧰 Create, parse, or convert PSSH headers with ease -- 🗃️ User-friendly YAML configuration -- ❤️ Forever FOSS! - -## Installation - -```shell -$ pip install pywidevine -``` - -> **Note** -If pip gives you a warning about a path not being in your PATH environment variable then promptly add that path then -close all open command prompt/terminal windows, or `pywidevine` CLI won't work as it will not be found. - -Voilà 🎉 — You now have the `pywidevine` package installed! -You can now import pywidevine in scripts ([see below](#usage)). -A command-line interface is also available, try `pywidevine --help`. - -## Usage - -The following is a minimal example of using pywidevine in a script to get a License for Bitmovin's -Art of Motion Demo. - -```py -from pywidevine.cdm import Cdm -from pywidevine.device import Device -from pywidevine.pssh import PSSH - -import requests - -# prepare pssh -pssh = PSSH("AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa" - "7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==") - -# load device -device = Device.load("C:/Path/To/A/Provision.wvd") - -# load cdm -cdm = Cdm.from_device(device) - -# open cdm session -session_id = cdm.open() - -# get license challenge -challenge = cdm.get_license_challenge(session_id, pssh) - -# send license challenge (assuming a generic license server SDK with no API front) -licence = requests.post("https://...", data=challenge) -licence.raise_for_status() - -# parse license challenge -cdm.parse_license(session_id, licence.content) - -# print keys -for key in cdm.get_keys(session_id): - print(f"[{key.type}] {key.kid.hex}:{key.key.hex()}") - -# close session, disposes of session data -cdm.close(session_id) -``` - -> **Note** -> There are various features not shown in this specific example like: -> -> - Privacy Mode -> - Setting Service Certificates -> - Remote CDMs and Serving -> - Choosing a License Type to request -> - Creating WVD files -> - and much more! -> -> Take a look at the methods available in the [Cdm class](/pywidevine/cdm.py) and their doc-strings for -> further information. For more examples see the [CLI functions](/pywidevine/main.py) which uses a lot -> of previously mentioned features. - -## Disclaimer - -1. This project requires a valid Google-provisioned Private Key and Client Identification blob which are not - provided by this project. -2. Public test provisions are available and provided by Google to use for testing projects such as this one. -3. License Servers have the ability to block requests from any provision, and are likely already blocking test - provisions on production endpoints. -4. This project does not condone piracy or any action against the terms of the DRM systems. -5. All efforts in this project have been the result of Reverse-Engineering, Publicly available research, and Trial - & Error. - -## Key and Output Security - -*Licenses, Content Keys, and Decrypted Data is not secure in this CDM implementation.* - -The Content Decryption Module is meant to do all downloading, decrypting, and decoding of content, not just license -acquisition. This Python implementation only does License Acquisition within the CDM. - -The section of which a 'Decrypt Frame' call is made would be more of a 'Decrypt File' in this implementation. Just -returning the original file in plain text defeats the point of the DRM. Even if 'Decrypt File' was somehow secure, the -Content Keys used to decrypt the files are already exposed to the caller anyway, allowing them to manually decrypt. - -An attack on a 'Decrypt Frame' system would be analogous to doing an HDMI capture or similar attack. This is because it -would require re-encoding the video by splicing each individual frame with the right frame-rate, syncing to audio, and -more. - -While a 'Decrypt Video' system would be analogous to downloading a Video and passing it through a script. Not much of -an attack if at all. The only protection against a system like this would be monitoring the provision and acquisitions -of licenses and prevent them. This can be done by revoking the device provision, or the user or their authorization to -the service. - -There isn't any immediate way to secure either Key or Decrypted information within a Python environment that is not -Hardware backed. Even if obfuscation or some other form of Security by Obscurity was used, this is a Software-based -Content Protection Module (in Python no less) with no hardware backed security. It would be incredibly trivial to break -any sort of protection against retrieving the original video data. - -Though, it's not impossible. Google's Chrome Browser CDM is a simple library extension file programmed in C++ that has -been improving its security using math and obscurity for years. It's getting harder and harder to break with its latest -versions only being beaten by Brute-force style methods. However, they have a huge team of very skilled workers, and -making a CDM in C++ has immediate security benefits and a lot of methods to obscure and obfuscate the code. - -## Contributors - - - - - -## Licensing - -This software is licensed under the terms of [GNU General Public License, Version 3.0](LICENSE). -You can find a copy of the license in the LICENSE file in the root folder. - -- Widevine Icon © Google. -- Props to the awesome community for their shared research and insight into the Widevine Protocol and Key Derivation. - -* * * - -© rlaphoenix 2022-2023 diff --git a/scripts/pywidevine/pyproject.toml b/scripts/pywidevine/pyproject.toml deleted file mode 100644 index 2e96c70..0000000 --- a/scripts/pywidevine/pyproject.toml +++ /dev/null @@ -1,86 +0,0 @@ -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - -[tool.poetry] -name = "pywidevine" -version = "1.8.0" -description = "Widevine CDM (Content Decryption Module) implementation in Python." -license = "GPL-3.0-only" -authors = ["rlaphoenix "] -readme = "README.md" -repository = "https://github.com/devine-dl/pywidevine" -keywords = ["python", "drm", "widevine", "google"] -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Intended Audience :: End Users/Desktop", - "Natural Language :: English", - "Operating System :: OS Independent", - "Topic :: Multimedia :: Video", - "Topic :: Security :: Cryptography", - "Topic :: Software Development :: Libraries :: Python Modules" -] -include = [ - { path = "CHANGELOG.md", format = "sdist" }, - { path = "README.md", format = "sdist" }, - { path = "LICENSE", format = "sdist" }, -] - -[tool.poetry.urls] -"Issues" = "https://github.com/devine-dl/pywidevine/issues" -"Discussions" = "https://github.com/devine-dl/pywidevine/discussions" -"Changelog" = "https://github.com/devine-dl/pywidevine/blob/master/CHANGELOG.md" - -[tool.poetry.dependencies] -python = ">=3.8,<4.0" -protobuf = "^4.25.1" -pycryptodome = "^3.19.0" -click = "^8.1.7" -requests = "^2.31.0" -Unidecode = "^1.3.7" -PyYAML = "^6.0.1" -aiohttp = {version = "^3.9.1", optional = true} - -[tool.poetry.group.dev.dependencies] -pre-commit = "^3.5.0" -mypy = "^1.7.1" -mypy-protobuf = "^3.5.0" -types-protobuf = "^4.24.0.4" -types-requests = "^2.31.0.10" -types-PyYAML = "^6.0.12.12" -isort = "^5.12.0" -ruff = "~0.1.7" - -[tool.poetry.extras] -serve = ["aiohttp"] - -[tool.poetry.scripts] -pywidevine = "pywidevine.main:main" - -[tool.ruff] -extend-exclude = [ - "*_pb2.py", - "*.pyi", -] -force-exclude = true -line-length = 120 -select = ["E4", "E7", "E9", "F", "W"] - -[tool.ruff.extend-per-file-ignores] -"pywidevine/__init__.py" = ["F403"] - -[tool.isort] -line_length = 118 -extend_skip_glob = ["*_pb2.py", "*.pyi"] - -[tool.mypy] -check_untyped_defs = true -disallow_incomplete_defs = true -disallow_untyped_defs = true -exclude = [ - '_pb2.pyi?$' # generated protobuffer files -] -follow_imports = "silent" -ignore_missing_imports = true -no_implicit_optional = true diff --git a/scripts/pywidevine/pywidevine/__init__.py b/scripts/pywidevine/pywidevine/__init__.py deleted file mode 100644 index 659ea25..0000000 --- a/scripts/pywidevine/pywidevine/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .cdm import * -from .device import * -from .key import * -from .pssh import * -from .remotecdm import * -from .session import * - -__version__ = "1.8.0" diff --git a/scripts/pywidevine/pywidevine/cdm.py b/scripts/pywidevine/pywidevine/cdm.py deleted file mode 100644 index 256cedf..0000000 --- a/scripts/pywidevine/pywidevine/cdm.py +++ /dev/null @@ -1,658 +0,0 @@ -from __future__ import annotations - -import base64 -import binascii -import random -import subprocess -import sys -import time -from pathlib import Path -from typing import Optional, Union -from uuid import UUID - -from Crypto.Cipher import AES, PKCS1_OAEP -from Crypto.Hash import CMAC, HMAC, SHA1, SHA256 -from Crypto.PublicKey import RSA -from Crypto.Random import get_random_bytes -from Crypto.Signature import pss -from Crypto.Util import Padding -from google.protobuf.message import DecodeError - -from pywidevine.device import Device, DeviceTypes -from pywidevine.exceptions import (InvalidContext, InvalidInitData, InvalidLicenseMessage, InvalidLicenseType, - InvalidSession, NoKeysLoaded, SignatureMismatch, TooManySessions) -from pywidevine.key import Key -from pywidevine.license_protocol_pb2 import (ClientIdentification, DrmCertificate, EncryptedClientIdentification, - License, LicenseRequest, LicenseType, SignedDrmCertificate, - SignedMessage) -from pywidevine.pssh import PSSH -from pywidevine.session import Session -from pywidevine.utils import get_binary_path - - -class Cdm: - uuid = UUID(bytes=b"\xed\xef\x8b\xa9\x79\xd6\x4a\xce\xa3\xc8\x27\xdc\xd5\x1d\x21\xed") - urn = f"urn:uuid:{uuid}" - key_format = urn - service_certificate_challenge = b"\x08\x04" - common_privacy_cert = ( - # Used by Google's production license server (license.google.com) - # Not publicly accessible directly, but a lot of services have their own gateways to it - "CAUSxwUKwQIIAxIQFwW5F8wSBIaLBjM6L3cqjBiCtIKSBSKOAjCCAQoCggEBAJntWzsyfateJO/DtiqVtZhSCtW8yzdQPgZFuBTYdrjfQFEE" - "Qa2M462xG7iMTnJaXkqeB5UpHVhYQCOn4a8OOKkSeTkwCGELbxWMh4x+Ib/7/up34QGeHleB6KRfRiY9FOYOgFioYHrc4E+shFexN6jWfM3r" - "M3BdmDoh+07svUoQykdJDKR+ql1DghjduvHK3jOS8T1v+2RC/THhv0CwxgTRxLpMlSCkv5fuvWCSmvzu9Vu69WTi0Ods18Vcc6CCuZYSC4NZ" - "7c4kcHCCaA1vZ8bYLErF8xNEkKdO7DevSy8BDFnoKEPiWC8La59dsPxebt9k+9MItHEbzxJQAZyfWgkCAwEAAToUbGljZW5zZS53aWRldmlu" - "ZS5jb20SgAOuNHMUtag1KX8nE4j7e7jLUnfSSYI83dHaMLkzOVEes8y96gS5RLknwSE0bv296snUE5F+bsF2oQQ4RgpQO8GVK5uk5M4PxL/C" - "CpgIqq9L/NGcHc/N9XTMrCjRtBBBbPneiAQwHL2zNMr80NQJeEI6ZC5UYT3wr8+WykqSSdhV5Cs6cD7xdn9qm9Nta/gr52u/DLpP3lnSq8x2" - "/rZCR7hcQx+8pSJmthn8NpeVQ/ypy727+voOGlXnVaPHvOZV+WRvWCq5z3CqCLl5+Gf2Ogsrf9s2LFvE7NVV2FvKqcWTw4PIV9Sdqrd+QLeF" - "Hd/SSZiAjjWyWOddeOrAyhb3BHMEwg2T7eTo/xxvF+YkPj89qPwXCYcOxF+6gjomPwzvofcJOxkJkoMmMzcFBDopvab5tDQsyN9UPLGhGC98" - "X/8z8QSQ+spbJTYLdgFenFoGq47gLwDS6NWYYQSqzE3Udf2W7pzk4ybyG4PHBYV3s4cyzdq8amvtE/sNSdOKReuHpfQ=") - staging_privacy_cert = ( - # Used by Google's staging license server (staging.google.com) - # This can be publicly accessed without authentication using https://cwip-shaka-proxy.appspot.com/no_auth - "CAUSxQUKvwIIAxIQKHA0VMAI9jYYredEPbbEyBiL5/mQBSKOAjCCAQoCggEBALUhErjQXQI/zF2V4sJRwcZJtBd82NK+7zVbsGdD3mYePSq8" - "MYK3mUbVX9wI3+lUB4FemmJ0syKix/XgZ7tfCsB6idRa6pSyUW8HW2bvgR0NJuG5priU8rmFeWKqFxxPZmMNPkxgJxiJf14e+baq9a1Nuip+" - "FBdt8TSh0xhbWiGKwFpMQfCB7/+Ao6BAxQsJu8dA7tzY8U1nWpGYD5LKfdxkagatrVEB90oOSYzAHwBTK6wheFC9kF6QkjZWt9/v70JIZ2fz" - "PvYoPU9CVKtyWJOQvuVYCPHWaAgNRdiTwryi901goMDQoJk87wFgRwMzTDY4E5SGvJ2vJP1noH+a2UMCAwEAAToSc3RhZ2luZy5nb29nbGUu" - "Y29tEoADmD4wNSZ19AunFfwkm9rl1KxySaJmZSHkNlVzlSlyH/iA4KrvxeJ7yYDa6tq/P8OG0ISgLIJTeEjMdT/0l7ARp9qXeIoA4qprhM19" - "ccB6SOv2FgLMpaPzIDCnKVww2pFbkdwYubyVk7jei7UPDe3BKTi46eA5zd4Y+oLoG7AyYw/pVdhaVmzhVDAL9tTBvRJpZjVrKH1lexjOY9Dv" - "1F/FJp6X6rEctWPlVkOyb/SfEJwhAa/K81uDLyiPDZ1Flg4lnoX7XSTb0s+Cdkxd2b9yfvvpyGH4aTIfat4YkF9Nkvmm2mU224R1hx0WjocL" - "sjA89wxul4TJPS3oRa2CYr5+DU4uSgdZzvgtEJ0lksckKfjAF0K64rPeytvDPD5fS69eFuy3Tq26/LfGcF96njtvOUA4P5xRFtICogySKe6W" - "nCUZcYMDtQ0BMMM1LgawFNg4VA+KDCJ8ABHg9bOOTimO0sswHrRWSWX1XF15dXolCk65yEqz5lOfa2/fVomeopkU") - root_signed_cert = SignedDrmCertificate() - root_signed_cert.ParseFromString(base64.b64decode( - "CpwDCAASAQAY3ZSIiwUijgMwggGKAoIBgQC0/jnDZZAD2zwRlwnoaM3yw16b8udNI7EQ24dl39z7nzWgVwNTTPZtNX2meNuzNtI/nECplSZy" - "f7i+Zt/FIZh4FRZoXS9GDkPLioQ5q/uwNYAivjQji6tTW3LsS7VIaVM+R1/9Cf2ndhOPD5LWTN+udqm62SIQqZ1xRdbX4RklhZxTmpfrhNfM" - "qIiCIHAmIP1+QFAn4iWTb7w+cqD6wb0ptE2CXMG0y5xyfrDpihc+GWP8/YJIK7eyM7l97Eu6iR8nuJuISISqGJIOZfXIbBH/azbkdDTKjDOx" - "+biOtOYS4AKYeVJeRTP/Edzrw1O6fGAaET0A+9K3qjD6T15Id1sX3HXvb9IZbdy+f7B4j9yCYEy/5CkGXmmMOROtFCXtGbLynwGCDVZEiMg1" - "7B8RsyTgWQ035Ec86kt/lzEcgXyUikx9aBWE/6UI/Rjn5yvkRycSEbgj7FiTPKwS0ohtQT3F/hzcufjUUT4H5QNvpxLoEve1zqaWVT94tGSC" - "UNIzX5ECAwEAARKAA1jx1k0ECXvf1+9dOwI5F/oUNnVKOGeFVxKnFO41FtU9v0KG9mkAds2T9Hyy355EzUzUrgkYU0Qy7OBhG+XaE9NVxd0a" - "y5AeflvG6Q8in76FAv6QMcxrA4S9IsRV+vXyCM1lQVjofSnaBFiC9TdpvPNaV4QXezKHcLKwdpyywxXRESYqI3WZPrl3IjINvBoZwdVlkHZV" - "dA8OaU1fTY8Zr9/WFjGUqJJfT7x6Mfiujq0zt+kw0IwKimyDNfiKgbL+HIisKmbF/73mF9BiC9yKRfewPlrIHkokL2yl4xyIFIPVxe9enz2F" - "RXPia1BSV0z7kmxmdYrWDRuu8+yvUSIDXQouY5OcCwEgqKmELhfKrnPsIht5rvagcizfB0fbiIYwFHghESKIrNdUdPnzJsKlVshWTwApHQh7" - "evuVicPumFSePGuUBRMS9nG5qxPDDJtGCHs9Mmpoyh6ckGLF7RC5HxclzpC5bc3ERvWjYhN0AqdipPpV2d7PouaAdFUGSdUCDA==" - )) - root_cert = DrmCertificate() - root_cert.ParseFromString(root_signed_cert.drm_certificate) - - MAX_NUM_OF_SESSIONS = 16 - - def __init__( - self, - device_type: Union[DeviceTypes, str], - system_id: int, - security_level: int, - client_id: ClientIdentification, - rsa_key: RSA.RsaKey - ): - """Initialize a Widevine Content Decryption Module (CDM).""" - if not device_type: - raise ValueError("Device Type must be provided") - if isinstance(device_type, str): - device_type = DeviceTypes[device_type] - if not isinstance(device_type, DeviceTypes): - raise TypeError(f"Expected device_type to be a {DeviceTypes!r} not {device_type!r}") - - if not system_id: - raise ValueError("System ID must be provided") - if not isinstance(system_id, int): - raise TypeError(f"Expected system_id to be a {int} not {system_id!r}") - - if not security_level: - raise ValueError("Security Level must be provided") - if not isinstance(security_level, int): - raise TypeError(f"Expected security_level to be a {int} not {security_level!r}") - - if not client_id: - raise ValueError("Client ID must be provided") - if not isinstance(client_id, ClientIdentification): - raise TypeError(f"Expected client_id to be a {ClientIdentification} not {client_id!r}") - - if not rsa_key: - raise ValueError("RSA Key must be provided") - if not isinstance(rsa_key, RSA.RsaKey): - raise TypeError(f"Expected rsa_key to be a {RSA.RsaKey} not {rsa_key!r}") - - self.device_type = device_type - self.system_id = system_id - self.security_level = security_level - self.__client_id = client_id - - self.__signer = pss.new(rsa_key) - self.__decrypter = PKCS1_OAEP.new(rsa_key) - - self.__sessions: dict[bytes, Session] = {} - - @classmethod - def from_device(cls, device: Device) -> Cdm: - """Initialize a Widevine CDM from a Widevine Device (.wvd) file.""" - return cls( - device_type=device.type, - system_id=device.system_id, - security_level=device.security_level, - client_id=device.client_id, - rsa_key=device.private_key - ) - - def open(self) -> bytes: - """ - Open a Widevine Content Decryption Module (CDM) session. - - Raises: - TooManySessions: If the session cannot be opened as limit has been reached. - """ - if len(self.__sessions) > self.MAX_NUM_OF_SESSIONS: - raise TooManySessions(f"Too many Sessions open ({self.MAX_NUM_OF_SESSIONS}).") - - session = Session(len(self.__sessions) + 1) - self.__sessions[session.id] = session - - return session.id - - def close(self, session_id: bytes) -> None: - """ - Close a Widevine Content Decryption Module (CDM) session. - - Parameters: - session_id: Session identifier. - - Raises: - InvalidSession: If the Session identifier is invalid. - """ - session = self.__sessions.get(session_id) - if not session: - raise InvalidSession(f"Session identifier {session_id!r} is invalid.") - del self.__sessions[session_id] - - def set_service_certificate(self, session_id: bytes, certificate: Optional[Union[bytes, str]]) -> Optional[str]: - """ - Set a Service Privacy Certificate for Privacy Mode. (optional but recommended) - - The Service Certificate is used to encrypt Client IDs in Licenses. This is also - known as Privacy Mode and may be required for some services or for some devices. - Chrome CDM requires it as of the enforcement of VMP (Verified Media Path). - - We reject direct DrmCertificates as they do not have signature verification and - cannot be verified. You must provide a SignedDrmCertificate or a SignedMessage - containing a SignedDrmCertificate. - - Parameters: - session_id: Session identifier. - certificate: SignedDrmCertificate (or SignedMessage containing one) in Base64 - or Bytes form obtained from the Service. Some services have their own, - but most use the common privacy cert, (common_privacy_cert). If None, it - will remove the current certificate. - - Raises: - InvalidSession: If the Session identifier is invalid. - DecodeError: If the certificate could not be parsed as a SignedDrmCertificate - nor a SignedMessage containing a SignedDrmCertificate. - SignatureMismatch: If the Signature of the SignedDrmCertificate does not - match the underlying DrmCertificate. - - Returns the Service Provider ID of the verified DrmCertificate if successful. - If certificate is None, it will return the now-unset certificate's Provider ID, - or None if no certificate was set yet. - """ - session = self.__sessions.get(session_id) - if not session: - raise InvalidSession(f"Session identifier {session_id!r} is invalid.") - - if certificate is None: - if session.service_certificate: - drm_certificate = DrmCertificate() - drm_certificate.ParseFromString(session.service_certificate.drm_certificate) - provider_id = drm_certificate.provider_id - else: - provider_id = None - session.service_certificate = None - return provider_id - - if isinstance(certificate, str): - try: - certificate = base64.b64decode(certificate) # assuming base64 - except binascii.Error: - raise DecodeError("Could not decode certificate string as Base64, expected bytes.") - elif not isinstance(certificate, bytes): - raise DecodeError(f"Expecting Certificate to be bytes, not {certificate!r}") - - signed_message = SignedMessage() - signed_drm_certificate = SignedDrmCertificate() - drm_certificate = DrmCertificate() - - try: - signed_message.ParseFromString(certificate) - if all( - # See https://github.com/devine-dl/pywidevine/issues/41 - bytes(chunk) == signed_message.SerializeToString() - for chunk in zip(*[iter(certificate)] * len(signed_message.SerializeToString())) - ): - signed_drm_certificate.ParseFromString(signed_message.msg) - else: - signed_drm_certificate.ParseFromString(certificate) - if signed_drm_certificate.SerializeToString() != certificate: - raise DecodeError("partial parse") - except DecodeError as e: - # could be a direct unsigned DrmCertificate, but reject those anyway - raise DecodeError(f"Could not parse certificate as a SignedDrmCertificate, {e}") - - try: - pss. \ - new(RSA.import_key(self.root_cert.public_key)). \ - verify( - msg_hash=SHA1.new(signed_drm_certificate.drm_certificate), - signature=signed_drm_certificate.signature - ) - except (ValueError, TypeError): - raise SignatureMismatch("Signature Mismatch on SignedDrmCertificate, rejecting certificate") - - try: - drm_certificate.ParseFromString(signed_drm_certificate.drm_certificate) - if drm_certificate.SerializeToString() != signed_drm_certificate.drm_certificate: - raise DecodeError("partial parse") - except DecodeError as e: - raise DecodeError(f"Could not parse signed certificate's message as a DrmCertificate, {e}") - - # must be stored as a SignedDrmCertificate as the signature needs to be kept for RemoteCdm - # if we store as DrmCertificate (no signature) then RemoteCdm cannot verify the Certificate - session.service_certificate = signed_drm_certificate - return drm_certificate.provider_id - - def get_service_certificate(self, session_id: bytes) -> Optional[SignedDrmCertificate]: - """ - Get the currently set Service Privacy Certificate of the Session. - - Parameters: - session_id: Session identifier. - - Raises: - InvalidSession: If the Session identifier is invalid. - - Returns the Service Certificate if one is set, otherwise None. - """ - session = self.__sessions.get(session_id) - if not session: - raise InvalidSession(f"Session identifier {session_id!r} is invalid.") - - return session.service_certificate - - def get_license_challenge( - self, - session_id: bytes, - pssh: PSSH, - license_type: str = "STREAMING", - privacy_mode: bool = True - ) -> bytes: - """ - Get a License Request (Challenge) to send to a License Server. - - Parameters: - session_id: Session identifier. - pssh: PSSH Object to get the init data from. - license_type: Type of License you wish to exchange, often `STREAMING`. - - "STREAMING": Normal one-time-use license. - - "OFFLINE": Offline-use licence, usually for Downloaded content. - - "AUTOMATIC": License type decision is left to provider. - privacy_mode: Encrypt the Client ID using the Privacy Certificate. If the - privacy certificate is not set yet, this does nothing. - - Raises: - InvalidSession: If the Session identifier is invalid. - InvalidInitData: If the Init Data (or PSSH box) provided is invalid. - InvalidLicenseType: If the type_ parameter value is not a License Type. It - must be a LicenseType enum, or a string/int representing the enum's keys - or values. - - Returns a SignedMessage containing a LicenseRequest message. It's signed with - the Private Key of the device provision. - """ - session = self.__sessions.get(session_id) - if not session: - raise InvalidSession(f"Session identifier {session_id!r} is invalid.") - - if not pssh: - raise InvalidInitData("A pssh must be provided.") - if not isinstance(pssh, PSSH): - raise InvalidInitData(f"Expected pssh to be a {PSSH}, not {pssh!r}") - - if not isinstance(license_type, str): - raise InvalidLicenseType(f"Expected license_type to be a {str}, not {license_type!r}") - if license_type not in LicenseType.keys(): - raise InvalidLicenseType( - f"Invalid license_type value of '{license_type}'. " - f"Available values: {LicenseType.keys()}" - ) - - if self.device_type == DeviceTypes.ANDROID: - # OEMCrypto's request_id seems to be in AES CTR Counter block form with no suffix - # Bytes 5-8 does not seem random, in real tests they have been consecutive \x00 or \xFF - # Real example: A0DCE548000000000500000000000000 - request_id = (get_random_bytes(4) + (b"\x00" * 4)) # (?) - request_id += session.number.to_bytes(8, "little") # counter - # as you can see in the real example, it is stored as uppercase hex and re-encoded - # it's really 16 bytes of data, but it's stored as a 32-char HEX string (32 bytes) - request_id = request_id.hex().upper().encode() - else: - request_id = get_random_bytes(16) - - license_request = LicenseRequest( - client_id=( - self.__client_id - ) if not (session.service_certificate and privacy_mode) else None, - encrypted_client_id=self.encrypt_client_id( - client_id=self.__client_id, - service_certificate=session.service_certificate - ) if session.service_certificate and privacy_mode else None, - content_id=LicenseRequest.ContentIdentification( - widevine_pssh_data=LicenseRequest.ContentIdentification.WidevinePsshData( - pssh_data=[pssh.init_data], # either a WidevineCencHeader or custom data - license_type=license_type, - request_id=request_id - ) - ), - type="NEW", - request_time=int(time.time()), - protocol_version="VERSION_2_1", - key_control_nonce=random.randrange(1, 2 ** 31), - ).SerializeToString() - - signed_license_request = SignedMessage( - type="LICENSE_REQUEST", - msg=license_request, - signature=self.__signer.sign(SHA1.new(license_request)) - ).SerializeToString() - - session.context[request_id] = self.derive_context(license_request) - - return signed_license_request - - def parse_license(self, session_id: bytes, license_message: Union[SignedMessage, bytes, str]) -> None: - """ - Load Keys from a License Message from a License Server Response. - - License Messages can only be loaded a single time. An InvalidContext error will - be raised if you attempt to parse a License Message more than once. - - Parameters: - session_id: Session identifier. - license_message: A SignedMessage containing a License message. - - Raises: - InvalidSession: If the Session identifier is invalid. - InvalidLicenseMessage: The License message could not be decoded as a Signed - Message or License message. - InvalidContext: If the Session has no Context Data. This is likely to happen - if the License Challenge was not made by this CDM instance, or was not - by this CDM at all. It could also happen if the Session is closed after - calling parse_license but not before it got the context data. - SignatureMismatch: If the Signature of the License SignedMessage does not - match the underlying License. - """ - session = self.__sessions.get(session_id) - if not session: - raise InvalidSession(f"Session identifier {session_id!r} is invalid.") - - if not license_message: - raise InvalidLicenseMessage("Cannot parse an empty license_message") - - if isinstance(license_message, str): - try: - license_message = base64.b64decode(license_message) - except (binascii.Error, binascii.Incomplete) as e: - raise InvalidLicenseMessage(f"Could not decode license_message as Base64, {e}") - - if isinstance(license_message, bytes): - signed_message = SignedMessage() - try: - signed_message.ParseFromString(license_message) - if signed_message.SerializeToString() != license_message: - raise DecodeError(license_message) - except DecodeError as e: - raise InvalidLicenseMessage(f"Could not parse license_message as a SignedMessage, {e}") - license_message = signed_message - - if not isinstance(license_message, SignedMessage): - raise InvalidLicenseMessage(f"Expecting license_response to be a SignedMessage, got {license_message!r}") - - if license_message.type != SignedMessage.MessageType.Value("LICENSE"): - raise InvalidLicenseMessage( - f"Expecting a LICENSE message, not a " - f"'{SignedMessage.MessageType.Name(license_message.type)}' message." - ) - - licence = License() - licence.ParseFromString(license_message.msg) - - context = session.context.get(licence.id.request_id) - if not context: - raise InvalidContext("Cannot parse a license message without first making a license request") - - enc_key, mac_key_server, _ = self.derive_keys( - *context, - key=self.__decrypter.decrypt(license_message.session_key) - ) - - # 1. Explicitly use the original `license_message.msg` instead of a re-serializing from `licence` - # as some differences may end up in the output due to differences in the proto schema - # 2. The oemcrypto_core_message (unknown purpose) is part of the signature algorithm starting with - # OEM Crypto API v16 and if available, must be prefixed when HMAC'ing a signature. - - computed_signature = HMAC. \ - new(mac_key_server, digestmod=SHA256). \ - update(license_message.oemcrypto_core_message or b""). \ - update(license_message.msg). \ - digest() - - if license_message.signature != computed_signature: - raise SignatureMismatch("Signature Mismatch on License Message, rejecting license") - - session.keys = [ - Key.from_key_container(key, enc_key) - for key in licence.key - ] - - del session.context[licence.id.request_id] - - def get_keys(self, session_id: bytes, type_: Optional[Union[int, str]] = None) -> list[Key]: - """ - Get Keys from the loaded License message. - - Parameters: - session_id: Session identifier. - type_: (optional) Key Type to filter by and return. - - Raises: - InvalidSession: If the Session identifier is invalid. - TypeError: If the provided type_ is an unexpected value type. - ValueError: If the provided type_ is not a valid Key Type. - """ - session = self.__sessions.get(session_id) - if not session: - raise InvalidSession(f"Session identifier {session_id!r} is invalid.") - - try: - if isinstance(type_, str): - type_ = License.KeyContainer.KeyType.Value(type_) - elif isinstance(type_, int): - License.KeyContainer.KeyType.Name(type_) # only test - elif type_ is not None: - raise TypeError(f"Expected type_ to be a {License.KeyContainer.KeyType} or int, not {type_!r}") - except ValueError as e: - raise ValueError(f"Could not parse type_ as a {License.KeyContainer.KeyType}, {e}") - - return [ - key - for key in session.keys - if not type_ or key.type == License.KeyContainer.KeyType.Name(type_) - ] - - def decrypt( - self, - session_id: bytes, - input_file: Union[Path, str], - output_file: Union[Path, str], - temp_dir: Optional[Union[Path, str]] = None, - exists_ok: bool = False - ) -> int: - """ - Decrypt a Widevine-encrypted file using Shaka-packager. - Shaka-packager is much more stable than mp4decrypt. - - Parameters: - session_id: Session identifier. - input_file: File to be decrypted with Session's currently loaded keys. - output_file: Location to save decrypted file. - temp_dir: Directory to store temporary data while decrypting. - exists_ok: Allow overwriting the output_file if it exists. - - Raises: - ValueError: If the input or output paths have not been supplied or are - invalid. - FileNotFoundError: If the input file path does not exist. - FileExistsError: If the output file path already exists. Ignored if exists_ok - is set to True. - NoKeysLoaded: No License was parsed for this Session, No Keys available. - EnvironmentError: If the shaka-packager executable could not be found. - subprocess.CalledProcessError: If the shaka-packager call returned a non-zero - exit code. - """ - if not input_file: - raise ValueError("Cannot decrypt nothing, specify an input path") - if not output_file: - raise ValueError("Cannot decrypt nowhere, specify an output path") - - if not isinstance(input_file, (Path, str)): - raise ValueError(f"Expecting input_file to be a Path or str, got {input_file!r}") - if not isinstance(output_file, (Path, str)): - raise ValueError(f"Expecting output_file to be a Path or str, got {output_file!r}") - if not isinstance(temp_dir, (Path, str)) and temp_dir is not None: - raise ValueError(f"Expecting temp_dir to be a Path or str, got {temp_dir!r}") - - input_file = Path(input_file) - output_file = Path(output_file) - temp_dir_ = Path(temp_dir) if temp_dir else None - - if not input_file.is_file(): - raise FileNotFoundError(f"Input file does not exist, {input_file}") - if output_file.is_file() and not exists_ok: - raise FileExistsError(f"Output file already exists, {output_file}") - - session = self.__sessions.get(session_id) - if not session: - raise InvalidSession(f"Session identifier {session_id!r} is invalid.") - - if not session.keys: - raise NoKeysLoaded("No Keys are loaded yet, cannot decrypt") - - platform = {"win32": "win", "darwin": "osx"}.get(sys.platform, sys.platform) - executable = get_binary_path("shaka-packager", f"packager-{platform}", f"packager-{platform}-x64") - if not executable: - raise EnvironmentError("Shaka Packager executable not found but is required") - - args = [ - f"input={input_file},stream=0,output={output_file}", - "--enable_raw_key_decryption", - "--keys", ",".join([ - label - for i, key in enumerate(session.keys) - for label in [ - f"label=1_{i}:key_id={key.kid.hex}:key={key.key.hex()}", - # some services need the KID blanked, e.g., Apple TV+ - f"label=2_{i}:key_id={'0' * 32}:key={key.key.hex()}" - ] - if key.type == "CONTENT" - ]) - ] - - if temp_dir_: - temp_dir_.mkdir(parents=True, exist_ok=True) - args.extend(["--temp_dir", str(temp_dir_)]) - - return subprocess.check_call([executable, *args]) - - @staticmethod - def encrypt_client_id( - client_id: ClientIdentification, - service_certificate: Union[SignedDrmCertificate, DrmCertificate], - key: Optional[bytes] = None, - iv: Optional[bytes] = None - ) -> EncryptedClientIdentification: - """Encrypt the Client ID with the Service's Privacy Certificate.""" - privacy_key = key or get_random_bytes(16) - privacy_iv = iv or get_random_bytes(16) - - if isinstance(service_certificate, SignedDrmCertificate): - drm_certificate = DrmCertificate() - drm_certificate.ParseFromString(service_certificate.drm_certificate) - service_certificate = drm_certificate - if not isinstance(service_certificate, DrmCertificate): - raise ValueError(f"Expecting Service Certificate to be a DrmCertificate, not {service_certificate!r}") - - encrypted_client_id = EncryptedClientIdentification( - provider_id=service_certificate.provider_id, - service_certificate_serial_number=service_certificate.serial_number, - encrypted_client_id=AES. - new(privacy_key, AES.MODE_CBC, privacy_iv). - encrypt(Padding.pad(client_id.SerializeToString(), 16)), - encrypted_client_id_iv=privacy_iv, - encrypted_privacy_key=PKCS1_OAEP. - new(RSA.importKey(service_certificate.public_key)). - encrypt(privacy_key) - ) - - return encrypted_client_id - - @staticmethod - def derive_context(message: bytes) -> tuple[bytes, bytes]: - """Returns 2 Context Data used for computing the AES Encryption and HMAC Keys.""" - - def _get_enc_context(msg: bytes) -> bytes: - label = b"ENCRYPTION" - key_size = 16 * 8 # 128-bit - return label + b"\x00" + msg + key_size.to_bytes(4, "big") - - def _get_mac_context(msg: bytes) -> bytes: - label = b"AUTHENTICATION" - key_size = 32 * 8 * 2 # 512-bit - return label + b"\x00" + msg + key_size.to_bytes(4, "big") - - return _get_enc_context(message), _get_mac_context(message) - - @staticmethod - def derive_keys(enc_context: bytes, mac_context: bytes, key: bytes) -> tuple[bytes, bytes, bytes]: - """ - Returns 3 keys derived from the input message. - Key can either be a pre-provision device aes key, provision key, or a session key. - - For provisioning: - - enc: aes key used for unwrapping RSA key out of response - - mac_key_server: hmac-sha256 key used for verifying provisioning response - - mac_key_client: hmac-sha256 key used for signing provisioning request - - When used with a session key: - - enc: decrypting content and other keys - - mac_key_server: verifying response - - mac_key_client: renewals - - With key as pre-provision device key, it can be used to provision and get an - RSA device key and token/cert with key as session key (OAEP wrapped with the - post-provision RSA device key), it can be used to decrypt content and signing - keys and verify licenses. - """ - - def _derive(session_key: bytes, context: bytes, counter: int) -> bytes: - return CMAC. \ - new(session_key, ciphermod=AES). \ - update(counter.to_bytes(1, "big") + context). \ - digest() - - enc_key = _derive(key, enc_context, 1) - mac_key_server = _derive(key, mac_context, 1) - mac_key_server += _derive(key, mac_context, 2) - mac_key_client = _derive(key, mac_context, 3) - mac_key_client += _derive(key, mac_context, 4) - - return enc_key, mac_key_server, mac_key_client - - -__all__ = ("Cdm",) diff --git a/scripts/pywidevine/pywidevine/device.py b/scripts/pywidevine/pywidevine/device.py deleted file mode 100644 index e5c8a3a..0000000 --- a/scripts/pywidevine/pywidevine/device.py +++ /dev/null @@ -1,276 +0,0 @@ -from __future__ import annotations - -import json -import base64 -import logging -from enum import Enum -from pathlib import Path -from typing import Any, Optional, Union - -from construct import BitStruct, Bytes, Const, ConstructError, Container -from construct import Enum as CEnum -from construct import Int8ub, Int16ub -from construct import Optional as COptional -from construct import Padded, Padding, Struct, this -from Crypto.PublicKey import RSA -from google.protobuf.message import DecodeError - -from pywidevine.license_protocol_pb2 import ClientIdentification, DrmCertificate, FileHashes, SignedDrmCertificate - - -class DeviceTypes(Enum): - CHROME = 1 - ANDROID = 2 - PLAYREADY = 3 - - -class _Structures: - magic = Const(b"WVD") - - header = Struct( - "signature" / magic, - "version" / Int8ub - ) - - # - Removed vmp and vmp_len as it should already be within the Client ID - v2 = Struct( - "signature" / magic, - "version" / Const(Int8ub, 2), - "type_" / CEnum( - Int8ub, - **{t.name: t.value for t in DeviceTypes} - ), - "security_level" / Int8ub, - "flags" / Padded(1, COptional(BitStruct( - # no per-device flags yet - Padding(8) - ))), - "private_key_len" / Int16ub, - "private_key" / Bytes(this.private_key_len), - "client_id_len" / Int16ub, - "client_id" / Bytes(this.client_id_len) - ) - - # - Removed system_id as it can be retrieved from the Client ID's DRM Certificate - v1 = Struct( - "signature" / magic, - "version" / Const(Int8ub, 1), - "type_" / CEnum( - Int8ub, - **{t.name: t.value for t in DeviceTypes} - ), - "security_level" / Int8ub, - "flags" / Padded(1, COptional(BitStruct( - # no per-device flags yet - Padding(8) - ))), - "private_key_len" / Int16ub, - "private_key" / Bytes(this.private_key_len), - "client_id_len" / Int16ub, - "client_id" / Bytes(this.client_id_len), - "vmp_len" / Int16ub, - "vmp" / Bytes(this.vmp_len) - ) - - -class Device: - Structures = _Structures - supported_structure = Structures.v2 - - def __init__( - self, - *_: Any, - type_: DeviceTypes, - security_level: int, - flags: Optional[dict], - private_key: Optional[bytes], - client_id: Optional[bytes], - **__: Any - ): - """ - This is the device key data that is needed for the CDM (Content Decryption Module). - - Parameters: - type_: Device Type - security_level: Security level from 1 (the highest ranking) to 3 (the lowest ranking) - flags: Extra flags - private_key: Device Private Key - client_id: Device Client Identification Blob - """ - # *_,*__ is to ignore unwanted args, like signature and version from the struct - - if not client_id: - raise ValueError("Client ID is required, the WVD does not contain one or is malformed.") - if not private_key: - raise ValueError("Private Key is required, the WVD does not contain one or is malformed.") - - self.type = DeviceTypes[type_] if isinstance(type_, str) else type_ - self.security_level = security_level - self.flags = flags or {} - self.private_key = RSA.importKey(private_key) - self.client_id = ClientIdentification() - try: - self.client_id.ParseFromString(client_id) - if self.client_id.SerializeToString() != client_id: - raise DecodeError("partial parse") - except DecodeError as e: - raise DecodeError(f"Failed to parse client_id as a ClientIdentification, {e}") - - self.vmp = FileHashes() - if self.client_id.vmp_data: - try: - self.vmp.ParseFromString(self.client_id.vmp_data) - if self.vmp.SerializeToString() != self.client_id.vmp_data: - raise DecodeError("partial parse") - except DecodeError as e: - raise DecodeError(f"Failed to parse Client ID's VMP data as a FileHashes, {e}") - - signed_drm_certificate = SignedDrmCertificate() - drm_certificate = DrmCertificate() - - try: - signed_drm_certificate.ParseFromString(self.client_id.token) - if signed_drm_certificate.SerializeToString() != self.client_id.token: - raise DecodeError("partial parse") - except DecodeError as e: - raise DecodeError(f"Failed to parse the Signed DRM Certificate of the Client ID, {e}") - - try: - drm_certificate.ParseFromString(signed_drm_certificate.drm_certificate) - if drm_certificate.SerializeToString() != signed_drm_certificate.drm_certificate: - raise DecodeError("partial parse") - except DecodeError as e: - raise DecodeError(f"Failed to parse the DRM Certificate of the Client ID, {e}") - - self.system_id = drm_certificate.system_id - - def __repr__(self) -> str: - return "{name}({items})".format( - name=self.__class__.__name__, - items=", ".join([f"{k}={repr(v)}" for k, v in self.__dict__.items()]) - ) - - @classmethod - def loads(cls, data: Union[bytes, str]) -> Device: - if isinstance(data, str): - data = base64.b64decode(data) - if not isinstance(data, bytes): - raise ValueError(f"Expecting Bytes or Base64 input, got {data!r}") - return cls(**cls.supported_structure.parse(data)) - - @classmethod - def from_dir(cls, dir: Union[Path, str]) -> Device: - try: - with open(os.path.join(d, "wv.json")) as fd: - config = json.load(fd) - except FileNotFoundError: - raise FileNotFoundError("wv.json file is required") - - try: - with open(os.path.join(d, "device_private_key"), "rb") as fd: - private_key = fd.read() - except FileNotFoundError: - private_key = None - - with open(os.path.join(d, "device_client_id_blob"), "rb") as fd: - client_id = fd.read() - - try: - with open(os.path.join(d, "device_vmp_blob"), "rb") as fd: - vmp = fd.read() - except FileNotFoundError: - vmp = None - - return cls( - type=getattr(DeviceTypes, config["session_id_type"].upper()), - security_level=int(config["security_level"]), - flags={ - "send_key_control_nonce": config.get("send_key_control_nonce", config["session_id_type"] == "android"), - }, - private_key=private_key, - client_id=client_id, - vmp=vmp, - ) - - @classmethod - def load(cls, path: Union[Path, str]) -> Device: - if not isinstance(path, (Path, str)): - raise ValueError(f"Expecting Path object or path string, got {path!r}") - with Path(path).open(mode="rb") as f: - return cls(**cls.supported_structure.parse_stream(f)) - - def dumps(self) -> bytes: - private_key = self.private_key.export_key("DER") if self.private_key else None - return self.supported_structure.build(dict( - version=2, - type_=self.type.value, - security_level=self.security_level, - flags=self.flags, - private_key_len=len(private_key) if private_key else 0, - private_key=private_key, - client_id_len=len(self.client_id.SerializeToString()) if self.client_id else 0, - client_id=self.client_id.SerializeToString() if self.client_id else None - )) - - def dump(self, path: Union[Path, str]) -> None: - if not isinstance(path, (Path, str)): - raise ValueError(f"Expecting Path object or path string, got {path!r}") - path = Path(path) - path.parent.mkdir(parents=True, exist_ok=True) - path.write_bytes(self.dumps()) - - @classmethod - def migrate(cls, data: Union[bytes, str]) -> Device: - if isinstance(data, str): - data = base64.b64decode(data) - if not isinstance(data, bytes): - raise ValueError(f"Expecting Bytes or Base64 input, got {data!r}") - - header = _Structures.header.parse(data) - if header.version == 2: - raise ValueError("Device Data is already migrated to the latest version.") - if header.version == 0 or header.version > 2: - # we have never used version 0, likely data that just so happened to use the WVD magic - raise ValueError("Device Data does not seem to be a WVD file (v0).") - - if header.version == 1: # v1 to v2 - v1_struct = _Structures.v1.parse(data) - v1_struct.version = 2 # update version to 2 to allow loading - v1_struct.flags = Container() # blank flags that may have been used in v1 - - vmp = FileHashes() - if v1_struct.vmp: - try: - vmp.ParseFromString(v1_struct.vmp) - if vmp.SerializeToString() != v1_struct.vmp: - raise DecodeError("partial parse") - except DecodeError as e: - raise DecodeError(f"Failed to parse VMP data as FileHashes, {e}") - v1_struct.vmp = vmp - - client_id = ClientIdentification() - try: - client_id.ParseFromString(v1_struct.client_id) - if client_id.SerializeToString() != v1_struct.client_id: - raise DecodeError("partial parse") - except DecodeError as e: - raise DecodeError(f"Failed to parse VMP data as FileHashes, {e}") - - new_vmp_data = v1_struct.vmp.SerializeToString() - if client_id.vmp_data and client_id.vmp_data != new_vmp_data: - logging.getLogger("migrate").warning("Client ID already has Verified Media Path data") - client_id.vmp_data = new_vmp_data - v1_struct.client_id = client_id.SerializeToString() - - try: - data = _Structures.v2.build(v1_struct) - except ConstructError as e: - raise ValueError(f"Migration failed, {e}") - - try: - return cls.loads(data) - except ConstructError as e: - raise ValueError(f"Device Data seems to be corrupt or invalid, or migration failed, {e}") - - -__all__ = ("Device", "DeviceTypes") diff --git a/scripts/pywidevine/pywidevine/exceptions.py b/scripts/pywidevine/pywidevine/exceptions.py deleted file mode 100644 index 3d6c5c7..0000000 --- a/scripts/pywidevine/pywidevine/exceptions.py +++ /dev/null @@ -1,38 +0,0 @@ -class PyWidevineException(Exception): - """Exceptions used by pywidevine.""" - - -class TooManySessions(PyWidevineException): - """Too many Sessions are open.""" - - -class InvalidSession(PyWidevineException): - """No Session is open with the specified identifier.""" - - -class InvalidInitData(PyWidevineException): - """The Widevine Cenc Header Data is invalid or empty.""" - - -class InvalidLicenseType(PyWidevineException): - """The License Type is an Invalid Value.""" - - -class InvalidLicenseMessage(PyWidevineException): - """The License Message is Invalid or Missing.""" - - -class InvalidContext(PyWidevineException): - """The Context is Invalid or Missing.""" - - -class SignatureMismatch(PyWidevineException): - """The Signature did not match.""" - - -class NoKeysLoaded(PyWidevineException): - """No License was parsed for this Session, No Keys available.""" - - -class DeviceMismatch(PyWidevineException): - """The Remote CDMs Device information and the APIs Device information did not match.""" diff --git a/scripts/pywidevine/pywidevine/key.py b/scripts/pywidevine/pywidevine/key.py deleted file mode 100644 index c5f8b31..0000000 --- a/scripts/pywidevine/pywidevine/key.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -import base64 -from typing import Optional, Union -from uuid import UUID - -from Crypto.Cipher import AES -from Crypto.Util import Padding - -from pywidevine.license_protocol_pb2 import License - - -class Key: - def __init__(self, type_: str, kid: UUID, key: bytes, permissions: Optional[list[str]] = None): - self.type = type_ - self.kid = kid - self.key = key - self.permissions = permissions or [] - - def __repr__(self) -> str: - return "{name}({items})".format( - name=self.__class__.__name__, - items=", ".join([f"{k}={repr(v)}" for k, v in self.__dict__.items()]) - ) - - @classmethod - def from_key_container(cls, key: License.KeyContainer, enc_key: bytes) -> Key: - """Load Key from a KeyContainer object.""" - permissions = [] - if key.type == License.KeyContainer.KeyType.Value("OPERATOR_SESSION"): - for descriptor, value in key.operator_session_key_permissions.ListFields(): - if value == 1: - permissions.append(descriptor.name) - - return Key( - type_=License.KeyContainer.KeyType.Name(key.type), - kid=cls.kid_to_uuid(key.id), - key=Padding.unpad( - AES.new(enc_key, AES.MODE_CBC, iv=key.iv).decrypt(key.key), - 16 - ), - permissions=permissions - ) - - @staticmethod - def kid_to_uuid(kid: Union[str, bytes]) -> UUID: - """ - Convert a Key ID from a string or bytes to a UUID object. - At first this may seem very simple but some types of Key IDs - may not be 16 bytes and some may be decimal vs. hex. - """ - if isinstance(kid, str): - kid = base64.b64decode(kid) - if not kid: - kid = b"\x00" * 16 - - if kid.decode(errors="replace").isdigit(): - return UUID(int=int(kid.decode())) - - if len(kid) < 16: - kid += b"\x00" * (16 - len(kid)) - - return UUID(bytes=kid) - - -__all__ = ("Key",) diff --git a/scripts/pywidevine/pywidevine/license_protocol.proto b/scripts/pywidevine/pywidevine/license_protocol.proto deleted file mode 100644 index cd2fe4f..0000000 --- a/scripts/pywidevine/pywidevine/license_protocol.proto +++ /dev/null @@ -1,752 +0,0 @@ -syntax = "proto2"; - -package pywidevine_license_protocol; - -// need this if we are using libprotobuf-cpp-2.3.0-lite -option optimize_for = LITE_RUNTIME; - -option java_package = "com.rlaphoenix.pywidevine.protos"; - -enum LicenseType { - STREAMING = 1; - OFFLINE = 2; - // License type decision is left to provider. - AUTOMATIC = 3; -} - -enum PlatformVerificationStatus { - // The platform is not verified. - PLATFORM_UNVERIFIED = 0; - // Tampering detected on the platform. - PLATFORM_TAMPERED = 1; - // The platform has been verified by means of software. - PLATFORM_SOFTWARE_VERIFIED = 2; - // The platform has been verified by means of hardware (e.g. secure boot). - PLATFORM_HARDWARE_VERIFIED = 3; - // Platform verification was not performed. - PLATFORM_NO_VERIFICATION = 4; - // Platform and secure storage capability have been verified by means of - // software. - PLATFORM_SECURE_STORAGE_SOFTWARE_VERIFIED = 5; -} - -// LicenseIdentification is propagated from LicenseRequest to License, -// incrementing version with each iteration. -message LicenseIdentification { - optional bytes request_id = 1; - optional bytes session_id = 2; - optional bytes purchase_id = 3; - optional LicenseType type = 4; - optional int32 version = 5; - optional bytes provider_session_token = 6; -} - -message License { - message Policy { - // Indicates that playback of the content is allowed. - optional bool can_play = 1 [default = false]; - - // Indicates that the license may be persisted to non-volatile - // storage for offline use. - optional bool can_persist = 2 [default = false]; - - // Indicates that renewal of this license is allowed. - optional bool can_renew = 3 [default = false]; - - // For the |*duration*| fields, playback must halt when - // license_start_time (seconds since the epoch (UTC)) + - // license_duration_seconds is exceeded. A value of 0 - // indicates that there is no limit to the duration. - - // Indicates the rental window. - optional int64 rental_duration_seconds = 4 [default = 0]; - - // Indicates the viewing window, once playback has begun. - optional int64 playback_duration_seconds = 5 [default = 0]; - - // Indicates the time window for this specific license. - optional int64 license_duration_seconds = 6 [default = 0]; - - // The |renewal*| fields only apply if |can_renew| is true. - - // The window of time, in which playback is allowed to continue while - // renewal is attempted, yet unsuccessful due to backend problems with - // the license server. - optional int64 renewal_recovery_duration_seconds = 7 [default = 0]; - - // All renewal requests for this license shall be directed to the - // specified URL. - optional string renewal_server_url = 8; - - // How many seconds after license_start_time, before renewal is first - // attempted. - optional int64 renewal_delay_seconds = 9 [default = 0]; - - // Specifies the delay in seconds between subsequent license - // renewal requests, in case of failure. - optional int64 renewal_retry_interval_seconds = 10 [default = 0]; - - // Indicates that the license shall be sent for renewal when usage is - // started. - optional bool renew_with_usage = 11 [default = false]; - - // Indicates to client that license renewal and release requests ought to - // include ClientIdentification (client_id). - optional bool always_include_client_id = 12 [default = false]; - - // Duration of grace period before playback_duration_seconds (short window) - // goes into effect. Optional. - optional int64 play_start_grace_period_seconds = 13 [default = 0]; - - // Enables "soft enforcement" of playback_duration_seconds, letting the user - // finish playback even if short window expires. Optional. - optional bool soft_enforce_playback_duration = 14 [default = false]; - - // Enables "soft enforcement" of rental_duration_seconds. Initial playback - // must always start before rental duration expires. In order to allow - // subsequent playbacks to start after the rental duration expires, - // soft_enforce_playback_duration must be true. Otherwise, subsequent - // playbacks will not be allowed once rental duration expires. Optional. - optional bool soft_enforce_rental_duration = 15 [default = true]; - } - - message KeyContainer { - enum KeyType { - SIGNING = 1; // Exactly one key of this type must appear. - CONTENT = 2; // Content key. - KEY_CONTROL = 3; // Key control block for license renewals. No key. - OPERATOR_SESSION = 4; // wrapped keys for auxiliary crypto operations. - ENTITLEMENT = 5; // Entitlement keys. - OEM_CONTENT = 6; // Partner-specific content key. - } - - // The SecurityLevel enumeration allows the server to communicate the level - // of robustness required by the client, in order to use the key. - enum SecurityLevel { - // Software-based whitebox crypto is required. - SW_SECURE_CRYPTO = 1; - - // Software crypto and an obfuscated decoder is required. - SW_SECURE_DECODE = 2; - - // The key material and crypto operations must be performed within a - // hardware backed trusted execution environment. - HW_SECURE_CRYPTO = 3; - - // The crypto and decoding of content must be performed within a hardware - // backed trusted execution environment. - HW_SECURE_DECODE = 4; - - // The crypto, decoding and all handling of the media (compressed and - // uncompressed) must be handled within a hardware backed trusted - // execution environment. - HW_SECURE_ALL = 5; - } - - message KeyControl { - // |key_control| is documented in: - // Widevine Modular DRM Security Integration Guide for CENC - // If present, the key control must be communicated to the secure - // environment prior to any usage. This message is automatically generated - // by the Widevine License Server SDK. - optional bytes key_control_block = 1; - optional bytes iv = 2; - } - - message OutputProtection { - // Indicates whether HDCP is required on digital outputs, and which - // version should be used. - enum HDCP { - HDCP_NONE = 0; - HDCP_V1 = 1; - HDCP_V2 = 2; - HDCP_V2_1 = 3; - HDCP_V2_2 = 4; - HDCP_V2_3 = 5; - HDCP_NO_DIGITAL_OUTPUT = 0xff; - } - optional HDCP hdcp = 1 [default = HDCP_NONE]; - - // Indicate the CGMS setting to be inserted on analog output. - enum CGMS { - CGMS_NONE = 42; - COPY_FREE = 0; - COPY_ONCE = 2; - COPY_NEVER = 3; - } - optional CGMS cgms_flags = 2 [default = CGMS_NONE]; - - enum HdcpSrmRule { - HDCP_SRM_RULE_NONE = 0; - // In 'required_protection', this means most current SRM is required. - // Update the SRM on the device. If update cannot happen, - // do not allow the key. - // In 'requested_protection', this means most current SRM is requested. - // Update the SRM on the device. If update cannot happen, - // allow use of the key anyway. - CURRENT_SRM = 1; - } - optional HdcpSrmRule hdcp_srm_rule = 3 [default = HDCP_SRM_RULE_NONE]; - // Optional requirement to indicate analog output is not allowed. - optional bool disable_analog_output = 4 [default = false]; - // Optional requirement to indicate digital output is not allowed. - optional bool disable_digital_output = 5 [default = false]; - } - - message VideoResolutionConstraint { - // Minimum and maximum video resolutions in the range (height x width). - optional uint32 min_resolution_pixels = 1; - optional uint32 max_resolution_pixels = 2; - // Optional output protection requirements for this range. If not - // specified, the OutputProtection in the KeyContainer applies. - optional OutputProtection required_protection = 3; - } - - message OperatorSessionKeyPermissions { - // Permissions/key usage flags for operator service keys - // (type = OPERATOR_SESSION). - optional bool allow_encrypt = 1 [default = false]; - optional bool allow_decrypt = 2 [default = false]; - optional bool allow_sign = 3 [default = false]; - optional bool allow_signature_verify = 4 [default = false]; - } - - optional bytes id = 1; - optional bytes iv = 2; - optional bytes key = 3; - optional KeyType type = 4; - optional SecurityLevel level = 5 [default = SW_SECURE_CRYPTO]; - optional OutputProtection required_protection = 6; - // NOTE: Use of requested_protection is not recommended as it is only - // supported on a small number of platforms. - optional OutputProtection requested_protection = 7; - optional KeyControl key_control = 8; - optional OperatorSessionKeyPermissions operator_session_key_permissions = 9; - // Optional video resolution constraints. If the video resolution of the - // content being decrypted/decoded falls within one of the specified ranges, - // the optional required_protections may be applied. Otherwise an error will - // be reported. - // NOTE: Use of this feature is not recommended, as it is only supported on - // a small number of platforms. - repeated VideoResolutionConstraint video_resolution_constraints = 10; - // Optional flag to indicate the key must only be used if the client - // supports anti rollback of the user table. Content provider can query the - // client capabilities to determine if the client support this feature. - optional bool anti_rollback_usage_table = 11 [default = false]; - // Optional not limited to commonly known track types such as SD, HD. - // It can be some provider defined label to identify the track. - optional string track_label = 12; - } - - optional LicenseIdentification id = 1; - optional Policy policy = 2; - repeated KeyContainer key = 3; - // Time of the request in seconds (UTC) as set in - // LicenseRequest.request_time. If this time is not set in the request, - // the local time at the license service is used in this field. - optional int64 license_start_time = 4; - optional bool remote_attestation_verified = 5 [default = false]; - // Client token generated by the content provider. Optional. - optional bytes provider_client_token = 6; - // 4cc code specifying the CENC protection scheme as defined in the CENC 3.0 - // specification. Propagated from Widevine PSSH box. Optional. - optional uint32 protection_scheme = 7; - // 8 byte verification field "HDCPDATA" followed by unsigned 32 bit minimum - // HDCP SRM version (whether the version is for HDCP1 SRM or HDCP2 SRM - // depends on client max_hdcp_version). - // Additional details can be found in Widevine Modular DRM Security - // Integration Guide for CENC. - optional bytes srm_requirement = 8; - // If present this contains a signed SRM file (either HDCP1 SRM or HDCP2 SRM - // depending on client max_hdcp_version) that should be installed on the - // client device. - optional bytes srm_update = 9; - // Indicates the status of any type of platform verification performed by the - // server. - optional PlatformVerificationStatus platform_verification_status = 10 - [default = PLATFORM_NO_VERIFICATION]; - // IDs of the groups for which keys are delivered in this license, if any. - repeated bytes group_ids = 11; -} - -enum ProtocolVersion { - VERSION_2_0 = 20; - VERSION_2_1 = 21; - VERSION_2_2 = 22; -} - -message LicenseRequest { - message ContentIdentification { - message WidevinePsshData { - repeated bytes pssh_data = 1; - optional LicenseType license_type = 2; - optional bytes request_id = 3; // Opaque, client-specified. - } - - message WebmKeyId { - optional bytes header = 1; - optional LicenseType license_type = 2; - optional bytes request_id = 3; // Opaque, client-specified. - } - - message ExistingLicense { - optional LicenseIdentification license_id = 1; - optional int64 seconds_since_started = 2; - optional int64 seconds_since_last_played = 3; - optional bytes session_usage_table_entry = 4; - } - - message InitData { - enum InitDataType { - CENC = 1; - WEBM = 2; - } - - optional InitDataType init_data_type = 1 [default = CENC]; - optional bytes init_data = 2; - optional LicenseType license_type = 3; - optional bytes request_id = 4; - } - - oneof content_id_variant { - // Exactly one of these must be present. - WidevinePsshData widevine_pssh_data = 1; - WebmKeyId webm_key_id = 2; - ExistingLicense existing_license = 3; - InitData init_data = 4; - } - } - - enum RequestType { - NEW = 1; - RENEWAL = 2; - RELEASE = 3; - } - - // The client_id provides information authenticating the calling device. It - // contains the Widevine keybox token that was installed on the device at the - // factory. This field or encrypted_client_id below is required for a valid - // license request, but both should never be present in the same request. - optional ClientIdentification client_id = 1; - optional ContentIdentification content_id = 2; - optional RequestType type = 3; - // Time of the request in seconds (UTC) as set by the client. - optional int64 request_time = 4; - // Old-style decimal-encoded string key control nonce. - optional bytes key_control_nonce_deprecated = 5; - optional ProtocolVersion protocol_version = 6 [default = VERSION_2_0]; - // New-style uint32 key control nonce, please use instead of - // key_control_nonce_deprecated. - optional uint32 key_control_nonce = 7; - // Encrypted ClientIdentification message, used for privacy purposes. - optional EncryptedClientIdentification encrypted_client_id = 8; -} - -message MetricData { - enum MetricType { - // The time spent in the 'stage', specified in microseconds. - LATENCY = 1; - // The UNIX epoch timestamp at which the 'stage' was first accessed in - // microseconds. - TIMESTAMP = 2; - } - - message TypeValue { - optional MetricType type = 1; - // The value associated with 'type'. For example if type == LATENCY, the - // value would be the time in microseconds spent in this 'stage'. - optional int64 value = 2 [default = 0]; - } - - // 'stage' that is currently processing the SignedMessage. Required. - optional string stage_name = 1; - // metric and associated value. - repeated TypeValue metric_data = 2; -} - -message VersionInfo { - // License SDK version reported by the Widevine License SDK. This field - // is populated automatically by the SDK. - optional string license_sdk_version = 1; - // Version of the service hosting the license SDK. This field is optional. - // It may be provided by the hosting service. - optional string license_service_version = 2; -} - -message SignedMessage { - enum MessageType { - LICENSE_REQUEST = 1; - LICENSE = 2; - ERROR_RESPONSE = 3; - SERVICE_CERTIFICATE_REQUEST = 4; - SERVICE_CERTIFICATE = 5; - SUB_LICENSE = 6; - CAS_LICENSE_REQUEST = 7; - CAS_LICENSE = 8; - EXTERNAL_LICENSE_REQUEST = 9; - EXTERNAL_LICENSE = 10; - } - - enum SessionKeyType { - UNDEFINED = 0; - WRAPPED_AES_KEY = 1; - EPHERMERAL_ECC_PUBLIC_KEY = 2; - } - optional MessageType type = 1; - optional bytes msg = 2; - // Required field that contains the signature of the bytes of msg. - // For license requests, the signing algorithm is determined by the - // certificate contained in the request. - // For license responses, the signing algorithm is HMAC with signing key based - // on |session_key|. - optional bytes signature = 3; - // If populated, the contents of this field will be signaled by the - // |session_key_type| type. If the |session_key_type| is WRAPPED_AES_KEY the - // key is the bytes of an encrypted AES key. If the |session_key_type| is - // EPHERMERAL_ECC_PUBLIC_KEY the field contains the bytes of an RFC5208 ASN1 - // serialized ECC public key. - optional bytes session_key = 4; - // Remote attestation data which will be present in the initial license - // request for ChromeOS client devices operating in verified mode. Remote - // attestation challenge data is |msg| field above. Optional. - optional bytes remote_attestation = 5; - - repeated MetricData metric_data = 6; - // Version information from the SDK and license service. This information is - // provided in the license response. - optional VersionInfo service_version_info = 7; - // Optional field that contains the algorithm type used to generate the - // session_key and signature in a LICENSE message. - optional SessionKeyType session_key_type = 8 [default = WRAPPED_AES_KEY]; - // The core message is the simple serialization of fields used by OEMCrypto. - // This field was introduced in OEMCrypto API v16. - optional bytes oemcrypto_core_message = 9; -} - -enum HashAlgorithmProto { - // Unspecified hash algorithm: SHA_256 shall be used for ECC based algorithms - // and SHA_1 shall be used otherwise. - HASH_ALGORITHM_UNSPECIFIED = 0; - HASH_ALGORITHM_SHA_1 = 1; - HASH_ALGORITHM_SHA_256 = 2; - HASH_ALGORITHM_SHA_384 = 3; -} - -// ClientIdentification message used to authenticate the client device. -message ClientIdentification { - enum TokenType { - KEYBOX = 0; - DRM_DEVICE_CERTIFICATE = 1; - REMOTE_ATTESTATION_CERTIFICATE = 2; - OEM_DEVICE_CERTIFICATE = 3; - } - - message NameValue { - optional string name = 1; - optional string value = 2; - } - - // Capabilities which not all clients may support. Used for the license - // exchange protocol only. - message ClientCapabilities { - enum HdcpVersion { - HDCP_NONE = 0; - HDCP_V1 = 1; - HDCP_V2 = 2; - HDCP_V2_1 = 3; - HDCP_V2_2 = 4; - HDCP_V2_3 = 5; - HDCP_NO_DIGITAL_OUTPUT = 0xff; - } - - enum CertificateKeyType { - RSA_2048 = 0; - RSA_3072 = 1; - ECC_SECP256R1 = 2; - ECC_SECP384R1 = 3; - ECC_SECP521R1 = 4; - } - - enum AnalogOutputCapabilities { - ANALOG_OUTPUT_UNKNOWN = 0; - ANALOG_OUTPUT_NONE = 1; - ANALOG_OUTPUT_SUPPORTED = 2; - ANALOG_OUTPUT_SUPPORTS_CGMS_A = 3; - } - - optional bool client_token = 1 [default = false]; - optional bool session_token = 2 [default = false]; - optional bool video_resolution_constraints = 3 [default = false]; - optional HdcpVersion max_hdcp_version = 4 [default = HDCP_NONE]; - optional uint32 oem_crypto_api_version = 5; - // Client has hardware support for protecting the usage table, such as - // storing the generation number in secure memory. For Details, see: - // Widevine Modular DRM Security Integration Guide for CENC - optional bool anti_rollback_usage_table = 6 [default = false]; - // The client shall report |srm_version| if available. - optional uint32 srm_version = 7; - // A device may have SRM data, and report a version, but may not be capable - // of updating SRM data. - optional bool can_update_srm = 8 [default = false]; - repeated CertificateKeyType supported_certificate_key_type = 9; - optional AnalogOutputCapabilities analog_output_capabilities = 10 - [default = ANALOG_OUTPUT_UNKNOWN]; - optional bool can_disable_analog_output = 11 [default = false]; - // Clients can indicate a performance level supported by OEMCrypto. - // This will allow applications and providers to choose an appropriate - // quality of content to serve. Currently defined tiers are - // 1 (low), 2 (medium) and 3 (high). Any other value indicates that - // the resource rating is unavailable or reporting erroneous values - // for that device. For details see, - // Widevine Modular DRM Security Integration Guide for CENC - optional uint32 resource_rating_tier = 12 [default = 0]; - } - - message ClientCredentials { - optional TokenType type = 1 [default = KEYBOX]; - optional bytes token = 2; - } - - // Type of factory-provisioned device root of trust. Optional. - optional TokenType type = 1 [default = KEYBOX]; - // Factory-provisioned device root of trust. Required. - optional bytes token = 2; - // Optional client information name/value pairs. - repeated NameValue client_info = 3; - // Client token generated by the content provider. Optional. - optional bytes provider_client_token = 4; - // Number of licenses received by the client to which the token above belongs. - // Only present if client_token is specified. - optional uint32 license_counter = 5; - // List of non-baseline client capabilities. - optional ClientCapabilities client_capabilities = 6; - // Serialized VmpData message. Optional. - optional bytes vmp_data = 7; - // Optional field that may contain additional provisioning credentials. - repeated ClientCredentials device_credentials = 8; -} - -// EncryptedClientIdentification message used to hold ClientIdentification -// messages encrypted for privacy purposes. -message EncryptedClientIdentification { - // Provider ID for which the ClientIdentifcation is encrypted (owner of - // service certificate). - optional string provider_id = 1; - // Serial number for the service certificate for which ClientIdentification is - // encrypted. - optional bytes service_certificate_serial_number = 2; - // Serialized ClientIdentification message, encrypted with the privacy key - // using AES-128-CBC with PKCS#5 padding. - optional bytes encrypted_client_id = 3; - // Initialization vector needed to decrypt encrypted_client_id. - optional bytes encrypted_client_id_iv = 4; - // AES-128 privacy key, encrypted with the service public key using RSA-OAEP. - optional bytes encrypted_privacy_key = 5; -} - -// DRM certificate definition for user devices, intermediate, service, and root -// certificates. -message DrmCertificate { - enum Type { - ROOT = 0; // ProtoBestPractices: ignore. - DEVICE_MODEL = 1; - DEVICE = 2; - SERVICE = 3; - PROVISIONER = 4; - } - enum ServiceType { - UNKNOWN_SERVICE_TYPE = 0; - LICENSE_SERVER_SDK = 1; - LICENSE_SERVER_PROXY_SDK = 2; - PROVISIONING_SDK = 3; - CAS_PROXY_SDK = 4; - } - enum Algorithm { - UNKNOWN_ALGORITHM = 0; - RSA = 1; - ECC_SECP256R1 = 2; - ECC_SECP384R1 = 3; - ECC_SECP521R1 = 4; - } - - message EncryptionKey { - // Device public key. PKCS#1 ASN.1 DER-encoded. Required. - optional bytes public_key = 1; - // Required. The algorithm field contains the curve used to create the - // |public_key| if algorithm is one of the ECC types. - // The |algorithm| is used for both to determine the if the certificate is - // ECC or RSA. The |algorithm| also specifies the parameters that were used - // to create |public_key| and are used to create an ephemeral session key. - optional Algorithm algorithm = 2 [default = RSA]; - } - - // Type of certificate. Required. - optional Type type = 1; - // 128-bit globally unique serial number of certificate. - // Value is 0 for root certificate. Required. - optional bytes serial_number = 2; - // POSIX time, in seconds, when the certificate was created. Required. - optional uint32 creation_time_seconds = 3; - // POSIX time, in seconds, when the certificate should expire. Value of zero - // denotes indefinite expiry time. For more information on limited lifespan - // DRM certificates see (go/limited-lifespan-drm-certificates). - optional uint32 expiration_time_seconds = 12; - // Device public key. PKCS#1 ASN.1 DER-encoded. Required. - optional bytes public_key = 4; - // Widevine system ID for the device. Required for intermediate and - // user device certificates. - optional uint32 system_id = 5; - // Deprecated field, which used to indicate whether the device was a test - // (non-production) device. The test_device field in ProvisionedDeviceInfo - // below should be observed instead. - optional bool test_device_deprecated = 6 [deprecated = true]; - // Service identifier (web origin) for the provider which owns the - // certificate. Required for service and provisioner certificates. - optional string provider_id = 7; - // This field is used only when type = SERVICE to specify which SDK uses - // service certificate. This repeated field is treated as a set. A certificate - // may be used for the specified service SDK if the appropriate ServiceType - // is specified in this field. - repeated ServiceType service_types = 8; - // Required. The algorithm field contains the curve used to create the - // |public_key| if algorithm is one of the ECC types. - // The |algorithm| is used for both to determine the if the certificate is ECC - // or RSA. The |algorithm| also specifies the parameters that were used to - // create |public_key| and are used to create an ephemeral session key. - optional Algorithm algorithm = 9 [default = RSA]; - // Optional. May be present in DEVICE certificate types. This is the root - // of trust identifier that holds an encrypted value that identifies the - // keybox or other root of trust that was used to provision a DEVICE drm - // certificate. - optional bytes rot_id = 10; - // Optional. May be present in devices that explicitly support dual keys. When - // present the |public_key| is used for verification of received license - // request messages. - optional EncryptionKey encryption_key = 11; -} - -// DrmCertificate signed by a higher (CA) DRM certificate. -message SignedDrmCertificate { - // Serialized certificate. Required. - optional bytes drm_certificate = 1; - // Signature of certificate. Signed with root or intermediate - // certificate specified below. Required. - optional bytes signature = 2; - // SignedDrmCertificate used to sign this certificate. - optional SignedDrmCertificate signer = 3; - // Optional field that indicates the hash algorithm used in signature scheme. - optional HashAlgorithmProto hash_algorithm = 4; -} - -message WidevinePsshData { - enum Type { - SINGLE = 0; // Single PSSH to be used to retrieve content keys. - ENTITLEMENT = 1; // Primary PSSH used to retrieve entitlement keys. - ENTITLED_KEY = 2; // Secondary PSSH containing entitled key(s). - } - - message EntitledKey { - // ID of entitlement key used for wrapping |key|. - optional bytes entitlement_key_id = 1; - // ID of the entitled key. - optional bytes key_id = 2; - // Wrapped key. Required. - optional bytes key = 3; - // IV used for wrapping |key|. Required. - optional bytes iv = 4; - // Size of entitlement key used for wrapping |key|. - optional uint32 entitlement_key_size_bytes = 5 [default = 32]; - } - - // Entitlement or content key IDs. Can onnly present in SINGLE or ENTITLEMENT - // PSSHs. May be repeated to facilitate delivery of multiple keys in a - // single license. Cannot be used in conjunction with content_id or - // group_ids, which are the preferred mechanism. - repeated bytes key_ids = 2; - - // Content identifier which may map to multiple entitlement or content key - // IDs to facilitate the delivery of multiple keys in a single license. - // Cannot be present in conjunction with key_ids, but if used must be in all - // PSSHs. - optional bytes content_id = 4; - - // Crypto period index, for media using key rotation. Always corresponds to - // The content key period. This means that if using entitlement licensing - // the ENTITLED_KEY PSSHs will have sequential crypto_period_index's, whereas - // the ENTITELEMENT PSSHs will have gaps in the sequence. Required if doing - // key rotation. - optional uint32 crypto_period_index = 7; - - // Protection scheme identifying the encryption algorithm. The protection - // scheme is represented as a uint32 value. The uint32 contains 4 bytes each - // representing a single ascii character in one of the 4CC protection scheme - // values. To be deprecated in favor of signaling from content. - // 'cenc' (AES-CTR) protection_scheme = 0x63656E63, - // 'cbc1' (AES-CBC) protection_scheme = 0x63626331, - // 'cens' (AES-CTR pattern encryption) protection_scheme = 0x63656E73, - // 'cbcs' (AES-CBC pattern encryption) protection_scheme = 0x63626373. - optional uint32 protection_scheme = 9; - - // Optional. For media using key rotation, this represents the duration - // of each crypto period in seconds. - optional uint32 crypto_period_seconds = 10; - - // Type of PSSH. Required if not SINGLE. - optional Type type = 11 [default = SINGLE]; - - // Key sequence for Widevine-managed keys. Optional. - optional uint32 key_sequence = 12; - - // Group identifiers for all groups to which the content belongs. This can - // be used to deliver licenses to unlock multiple titles / channels. - // Optional, and may only be present in ENTITLEMENT and ENTITLED_KEY PSSHs, and - // not in conjunction with key_ids. - repeated bytes group_ids = 13; - - // Copy/copies of the content key used to decrypt the media stream in which - // the PSSH box is embedded, each wrapped with a different entitlement key. - // May also contain sub-licenses to support devices with OEMCrypto 13 or - // older. May be repeated if using group entitlement keys. Present only in - // PSSHs of type ENTITLED_KEY. - repeated EntitledKey entitled_keys = 14; - - // Video feature identifier, which is used in conjunction with |content_id| - // to determine the set of keys to be returned in the license. Cannot be - // present in conjunction with |key_ids|. - // Current values are "HDR". - optional string video_feature = 15; - - //////////////////////////// Deprecated Fields //////////////////////////// - enum Algorithm { - UNENCRYPTED = 0; - AESCTR = 1; - }; - optional Algorithm algorithm = 1 [deprecated = true]; - - // Content provider name. - optional string provider = 3 [deprecated = true]; - - // Track type. Acceptable values are SD, HD and AUDIO. Used to - // differentiate content keys used by an asset. - optional string track_type = 5 [deprecated = true]; - - // The name of a registered policy to be used for this asset. - optional string policy = 6 [deprecated = true]; - - // Optional protected context for group content. The grouped_license is a - // serialized SignedMessage. - optional bytes grouped_license = 8 [deprecated = true]; -} - -// File Hashes for Verified Media Path (VMP) support. -message FileHashes { - message Signature { - optional string filename = 1; - optional bool test_signing = 2; //0 - release, 1 - testing - optional bytes SHA512Hash = 3; - optional bool main_exe = 4; //0 for dlls, 1 for exe, this is field 3 in file - optional bytes signature = 5; - } - optional bytes signer = 1; - repeated Signature signatures = 2; -} diff --git a/scripts/pywidevine/pywidevine/license_protocol_pb2.py b/scripts/pywidevine/pywidevine/license_protocol_pb2.py deleted file mode 100644 index 92ae262..0000000 --- a/scripts/pywidevine/pywidevine/license_protocol_pb2.py +++ /dev/null @@ -1,143 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: license_protocol.proto -# Protobuf Python Version: 4.25.1 -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16license_protocol.proto\x12\x1bpywidevine_license_protocol\"\xbd\x01\n\x15LicenseIdentification\x12\x12\n\nrequest_id\x18\x01 \x01(\x0c\x12\x12\n\nsession_id\x18\x02 \x01(\x0c\x12\x13\n\x0bpurchase_id\x18\x03 \x01(\x0c\x12\x36\n\x04type\x18\x04 \x01(\x0e\x32(.pywidevine_license_protocol.LicenseType\x12\x0f\n\x07version\x18\x05 \x01(\x05\x12\x1e\n\x16provider_session_token\x18\x06 \x01(\x0c\"\xf1\x18\n\x07License\x12>\n\x02id\x18\x01 \x01(\x0b\x32\x32.pywidevine_license_protocol.LicenseIdentification\x12;\n\x06policy\x18\x02 \x01(\x0b\x32+.pywidevine_license_protocol.License.Policy\x12>\n\x03key\x18\x03 \x03(\x0b\x32\x31.pywidevine_license_protocol.License.KeyContainer\x12\x1a\n\x12license_start_time\x18\x04 \x01(\x03\x12*\n\x1bremote_attestation_verified\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1d\n\x15provider_client_token\x18\x06 \x01(\x0c\x12\x19\n\x11protection_scheme\x18\x07 \x01(\r\x12\x17\n\x0fsrm_requirement\x18\x08 \x01(\x0c\x12\x12\n\nsrm_update\x18\t \x01(\x0c\x12w\n\x1cplatform_verification_status\x18\n \x01(\x0e\x32\x37.pywidevine_license_protocol.PlatformVerificationStatus:\x18PLATFORM_NO_VERIFICATION\x12\x11\n\tgroup_ids\x18\x0b \x03(\x0c\x1a\xae\x04\n\x06Policy\x12\x17\n\x08\x63\x61n_play\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0b\x63\x61n_persist\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tcan_renew\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\"\n\x17rental_duration_seconds\x18\x04 \x01(\x03:\x01\x30\x12$\n\x19playback_duration_seconds\x18\x05 \x01(\x03:\x01\x30\x12#\n\x18license_duration_seconds\x18\x06 \x01(\x03:\x01\x30\x12,\n!renewal_recovery_duration_seconds\x18\x07 \x01(\x03:\x01\x30\x12\x1a\n\x12renewal_server_url\x18\x08 \x01(\t\x12 \n\x15renewal_delay_seconds\x18\t \x01(\x03:\x01\x30\x12)\n\x1erenewal_retry_interval_seconds\x18\n \x01(\x03:\x01\x30\x12\x1f\n\x10renew_with_usage\x18\x0b \x01(\x08:\x05\x66\x61lse\x12\'\n\x18\x61lways_include_client_id\x18\x0c \x01(\x08:\x05\x66\x61lse\x12*\n\x1fplay_start_grace_period_seconds\x18\r \x01(\x03:\x01\x30\x12-\n\x1esoft_enforce_playback_duration\x18\x0e \x01(\x08:\x05\x66\x61lse\x12*\n\x1csoft_enforce_rental_duration\x18\x0f \x01(\x08:\x04true\x1a\xbc\x10\n\x0cKeyContainer\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\n\n\x02iv\x18\x02 \x01(\x0c\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12G\n\x04type\x18\x04 \x01(\x0e\x32\x39.pywidevine_license_protocol.License.KeyContainer.KeyType\x12`\n\x05level\x18\x05 \x01(\x0e\x32?.pywidevine_license_protocol.License.KeyContainer.SecurityLevel:\x10SW_SECURE_CRYPTO\x12_\n\x13required_protection\x18\x06 \x01(\x0b\x32\x42.pywidevine_license_protocol.License.KeyContainer.OutputProtection\x12`\n\x14requested_protection\x18\x07 \x01(\x0b\x32\x42.pywidevine_license_protocol.License.KeyContainer.OutputProtection\x12Q\n\x0bkey_control\x18\x08 \x01(\x0b\x32<.pywidevine_license_protocol.License.KeyContainer.KeyControl\x12y\n operator_session_key_permissions\x18\t \x01(\x0b\x32O.pywidevine_license_protocol.License.KeyContainer.OperatorSessionKeyPermissions\x12q\n\x1cvideo_resolution_constraints\x18\n \x03(\x0b\x32K.pywidevine_license_protocol.License.KeyContainer.VideoResolutionConstraint\x12(\n\x19\x61nti_rollback_usage_table\x18\x0b \x01(\x08:\x05\x66\x61lse\x12\x13\n\x0btrack_label\x18\x0c \x01(\t\x1a\x33\n\nKeyControl\x12\x19\n\x11key_control_block\x18\x01 \x01(\x0c\x12\n\n\x02iv\x18\x02 \x01(\x0c\x1a\x9c\x05\n\x10OutputProtection\x12`\n\x04hdcp\x18\x01 \x01(\x0e\x32G.pywidevine_license_protocol.License.KeyContainer.OutputProtection.HDCP:\tHDCP_NONE\x12\x66\n\ncgms_flags\x18\x02 \x01(\x0e\x32G.pywidevine_license_protocol.License.KeyContainer.OutputProtection.CGMS:\tCGMS_NONE\x12y\n\rhdcp_srm_rule\x18\x03 \x01(\x0e\x32N.pywidevine_license_protocol.License.KeyContainer.OutputProtection.HdcpSrmRule:\x12HDCP_SRM_RULE_NONE\x12$\n\x15\x64isable_analog_output\x18\x04 \x01(\x08:\x05\x66\x61lse\x12%\n\x16\x64isable_digital_output\x18\x05 \x01(\x08:\x05\x66\x61lse\"y\n\x04HDCP\x12\r\n\tHDCP_NONE\x10\x00\x12\x0b\n\x07HDCP_V1\x10\x01\x12\x0b\n\x07HDCP_V2\x10\x02\x12\r\n\tHDCP_V2_1\x10\x03\x12\r\n\tHDCP_V2_2\x10\x04\x12\r\n\tHDCP_V2_3\x10\x05\x12\x1b\n\x16HDCP_NO_DIGITAL_OUTPUT\x10\xff\x01\"C\n\x04\x43GMS\x12\r\n\tCGMS_NONE\x10*\x12\r\n\tCOPY_FREE\x10\x00\x12\r\n\tCOPY_ONCE\x10\x02\x12\x0e\n\nCOPY_NEVER\x10\x03\"6\n\x0bHdcpSrmRule\x12\x16\n\x12HDCP_SRM_RULE_NONE\x10\x00\x12\x0f\n\x0b\x43URRENT_SRM\x10\x01\x1a\xba\x01\n\x19VideoResolutionConstraint\x12\x1d\n\x15min_resolution_pixels\x18\x01 \x01(\r\x12\x1d\n\x15max_resolution_pixels\x18\x02 \x01(\r\x12_\n\x13required_protection\x18\x03 \x01(\x0b\x32\x42.pywidevine_license_protocol.License.KeyContainer.OutputProtection\x1a\x9d\x01\n\x1dOperatorSessionKeyPermissions\x12\x1c\n\rallow_encrypt\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x1c\n\rallow_decrypt\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\nallow_sign\x18\x03 \x01(\x08:\x05\x66\x61lse\x12%\n\x16\x61llow_signature_verify\x18\x04 \x01(\x08:\x05\x66\x61lse\"l\n\x07KeyType\x12\x0b\n\x07SIGNING\x10\x01\x12\x0b\n\x07\x43ONTENT\x10\x02\x12\x0f\n\x0bKEY_CONTROL\x10\x03\x12\x14\n\x10OPERATOR_SESSION\x10\x04\x12\x0f\n\x0b\x45NTITLEMENT\x10\x05\x12\x0f\n\x0bOEM_CONTENT\x10\x06\"z\n\rSecurityLevel\x12\x14\n\x10SW_SECURE_CRYPTO\x10\x01\x12\x14\n\x10SW_SECURE_DECODE\x10\x02\x12\x14\n\x10HW_SECURE_CRYPTO\x10\x03\x12\x14\n\x10HW_SECURE_DECODE\x10\x04\x12\x11\n\rHW_SECURE_ALL\x10\x05\"\xbd\r\n\x0eLicenseRequest\x12\x44\n\tclient_id\x18\x01 \x01(\x0b\x32\x31.pywidevine_license_protocol.ClientIdentification\x12U\n\ncontent_id\x18\x02 \x01(\x0b\x32\x41.pywidevine_license_protocol.LicenseRequest.ContentIdentification\x12\x45\n\x04type\x18\x03 \x01(\x0e\x32\x37.pywidevine_license_protocol.LicenseRequest.RequestType\x12\x14\n\x0crequest_time\x18\x04 \x01(\x03\x12$\n\x1ckey_control_nonce_deprecated\x18\x05 \x01(\x0c\x12S\n\x10protocol_version\x18\x06 \x01(\x0e\x32,.pywidevine_license_protocol.ProtocolVersion:\x0bVERSION_2_0\x12\x19\n\x11key_control_nonce\x18\x07 \x01(\r\x12W\n\x13\x65ncrypted_client_id\x18\x08 \x01(\x0b\x32:.pywidevine_license_protocol.EncryptedClientIdentification\x1a\x8f\t\n\x15\x43ontentIdentification\x12p\n\x12widevine_pssh_data\x18\x01 \x01(\x0b\x32R.pywidevine_license_protocol.LicenseRequest.ContentIdentification.WidevinePsshDataH\x00\x12\x62\n\x0bwebm_key_id\x18\x02 \x01(\x0b\x32K.pywidevine_license_protocol.LicenseRequest.ContentIdentification.WebmKeyIdH\x00\x12m\n\x10\x65xisting_license\x18\x03 \x01(\x0b\x32Q.pywidevine_license_protocol.LicenseRequest.ContentIdentification.ExistingLicenseH\x00\x12_\n\tinit_data\x18\x04 \x01(\x0b\x32J.pywidevine_license_protocol.LicenseRequest.ContentIdentification.InitDataH\x00\x1ay\n\x10WidevinePsshData\x12\x11\n\tpssh_data\x18\x01 \x03(\x0c\x12>\n\x0clicense_type\x18\x02 \x01(\x0e\x32(.pywidevine_license_protocol.LicenseType\x12\x12\n\nrequest_id\x18\x03 \x01(\x0c\x1ao\n\tWebmKeyId\x12\x0e\n\x06header\x18\x01 \x01(\x0c\x12>\n\x0clicense_type\x18\x02 \x01(\x0e\x32(.pywidevine_license_protocol.LicenseType\x12\x12\n\nrequest_id\x18\x03 \x01(\x0c\x1a\xbe\x01\n\x0f\x45xistingLicense\x12\x46\n\nlicense_id\x18\x01 \x01(\x0b\x32\x32.pywidevine_license_protocol.LicenseIdentification\x12\x1d\n\x15seconds_since_started\x18\x02 \x01(\x03\x12!\n\x19seconds_since_last_played\x18\x03 \x01(\x03\x12!\n\x19session_usage_table_entry\x18\x04 \x01(\x0c\x1a\x8c\x02\n\x08InitData\x12u\n\x0einit_data_type\x18\x01 \x01(\x0e\x32W.pywidevine_license_protocol.LicenseRequest.ContentIdentification.InitData.InitDataType:\x04\x43\x45NC\x12\x11\n\tinit_data\x18\x02 \x01(\x0c\x12>\n\x0clicense_type\x18\x03 \x01(\x0e\x32(.pywidevine_license_protocol.LicenseType\x12\x12\n\nrequest_id\x18\x04 \x01(\x0c\"\"\n\x0cInitDataType\x12\x08\n\x04\x43\x45NC\x10\x01\x12\x08\n\x04WEBM\x10\x02\x42\x14\n\x12\x63ontent_id_variant\"0\n\x0bRequestType\x12\x07\n\x03NEW\x10\x01\x12\x0b\n\x07RENEWAL\x10\x02\x12\x0b\n\x07RELEASE\x10\x03\"\xf3\x01\n\nMetricData\x12\x12\n\nstage_name\x18\x01 \x01(\t\x12\x46\n\x0bmetric_data\x18\x02 \x03(\x0b\x32\x31.pywidevine_license_protocol.MetricData.TypeValue\x1a_\n\tTypeValue\x12@\n\x04type\x18\x01 \x01(\x0e\x32\x32.pywidevine_license_protocol.MetricData.MetricType\x12\x10\n\x05value\x18\x02 \x01(\x03:\x01\x30\"(\n\nMetricType\x12\x0b\n\x07LATENCY\x10\x01\x12\r\n\tTIMESTAMP\x10\x02\"K\n\x0bVersionInfo\x12\x1b\n\x13license_sdk_version\x18\x01 \x01(\t\x12\x1f\n\x17license_service_version\x18\x02 \x01(\t\"\xf6\x05\n\rSignedMessage\x12\x44\n\x04type\x18\x01 \x01(\x0e\x32\x36.pywidevine_license_protocol.SignedMessage.MessageType\x12\x0b\n\x03msg\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\x12\x13\n\x0bsession_key\x18\x04 \x01(\x0c\x12\x1a\n\x12remote_attestation\x18\x05 \x01(\x0c\x12<\n\x0bmetric_data\x18\x06 \x03(\x0b\x32\'.pywidevine_license_protocol.MetricData\x12\x46\n\x14service_version_info\x18\x07 \x01(\x0b\x32(.pywidevine_license_protocol.VersionInfo\x12\x64\n\x10session_key_type\x18\x08 \x01(\x0e\x32\x39.pywidevine_license_protocol.SignedMessage.SessionKeyType:\x0fWRAPPED_AES_KEY\x12\x1e\n\x16oemcrypto_core_message\x18\t \x01(\x0c\"\xec\x01\n\x0bMessageType\x12\x13\n\x0fLICENSE_REQUEST\x10\x01\x12\x0b\n\x07LICENSE\x10\x02\x12\x12\n\x0e\x45RROR_RESPONSE\x10\x03\x12\x1f\n\x1bSERVICE_CERTIFICATE_REQUEST\x10\x04\x12\x17\n\x13SERVICE_CERTIFICATE\x10\x05\x12\x0f\n\x0bSUB_LICENSE\x10\x06\x12\x17\n\x13\x43\x41S_LICENSE_REQUEST\x10\x07\x12\x0f\n\x0b\x43\x41S_LICENSE\x10\x08\x12\x1c\n\x18\x45XTERNAL_LICENSE_REQUEST\x10\t\x12\x14\n\x10\x45XTERNAL_LICENSE\x10\n\"S\n\x0eSessionKeyType\x12\r\n\tUNDEFINED\x10\x00\x12\x13\n\x0fWRAPPED_AES_KEY\x10\x01\x12\x1d\n\x19\x45PHERMERAL_ECC_PUBLIC_KEY\x10\x02\"\xc7\x0e\n\x14\x43lientIdentification\x12Q\n\x04type\x18\x01 \x01(\x0e\x32;.pywidevine_license_protocol.ClientIdentification.TokenType:\x06KEYBOX\x12\r\n\x05token\x18\x02 \x01(\x0c\x12P\n\x0b\x63lient_info\x18\x03 \x03(\x0b\x32;.pywidevine_license_protocol.ClientIdentification.NameValue\x12\x1d\n\x15provider_client_token\x18\x04 \x01(\x0c\x12\x17\n\x0flicense_counter\x18\x05 \x01(\r\x12\x61\n\x13\x63lient_capabilities\x18\x06 \x01(\x0b\x32\x44.pywidevine_license_protocol.ClientIdentification.ClientCapabilities\x12\x10\n\x08vmp_data\x18\x07 \x01(\x0c\x12_\n\x12\x64\x65vice_credentials\x18\x08 \x03(\x0b\x32\x43.pywidevine_license_protocol.ClientIdentification.ClientCredentials\x1a(\n\tNameValue\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x1a\xd6\x08\n\x12\x43lientCapabilities\x12\x1b\n\x0c\x63lient_token\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x1c\n\rsession_token\x18\x02 \x01(\x08:\x05\x66\x61lse\x12+\n\x1cvideo_resolution_constraints\x18\x03 \x01(\x08:\x05\x66\x61lse\x12u\n\x10max_hdcp_version\x18\x04 \x01(\x0e\x32P.pywidevine_license_protocol.ClientIdentification.ClientCapabilities.HdcpVersion:\tHDCP_NONE\x12\x1e\n\x16oem_crypto_api_version\x18\x05 \x01(\r\x12(\n\x19\x61nti_rollback_usage_table\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x0bsrm_version\x18\x07 \x01(\r\x12\x1d\n\x0e\x63\x61n_update_srm\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\x7f\n\x1esupported_certificate_key_type\x18\t \x03(\x0e\x32W.pywidevine_license_protocol.ClientIdentification.ClientCapabilities.CertificateKeyType\x12\x98\x01\n\x1a\x61nalog_output_capabilities\x18\n \x01(\x0e\x32].pywidevine_license_protocol.ClientIdentification.ClientCapabilities.AnalogOutputCapabilities:\x15\x41NALOG_OUTPUT_UNKNOWN\x12(\n\x19\x63\x61n_disable_analog_output\x18\x0b \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x14resource_rating_tier\x18\x0c \x01(\r:\x01\x30\"\x80\x01\n\x0bHdcpVersion\x12\r\n\tHDCP_NONE\x10\x00\x12\x0b\n\x07HDCP_V1\x10\x01\x12\x0b\n\x07HDCP_V2\x10\x02\x12\r\n\tHDCP_V2_1\x10\x03\x12\r\n\tHDCP_V2_2\x10\x04\x12\r\n\tHDCP_V2_3\x10\x05\x12\x1b\n\x16HDCP_NO_DIGITAL_OUTPUT\x10\xff\x01\"i\n\x12\x43\x65rtificateKeyType\x12\x0c\n\x08RSA_2048\x10\x00\x12\x0c\n\x08RSA_3072\x10\x01\x12\x11\n\rECC_SECP256R1\x10\x02\x12\x11\n\rECC_SECP384R1\x10\x03\x12\x11\n\rECC_SECP521R1\x10\x04\"\x8d\x01\n\x18\x41nalogOutputCapabilities\x12\x19\n\x15\x41NALOG_OUTPUT_UNKNOWN\x10\x00\x12\x16\n\x12\x41NALOG_OUTPUT_NONE\x10\x01\x12\x1b\n\x17\x41NALOG_OUTPUT_SUPPORTED\x10\x02\x12!\n\x1d\x41NALOG_OUTPUT_SUPPORTS_CGMS_A\x10\x03\x1au\n\x11\x43lientCredentials\x12Q\n\x04type\x18\x01 \x01(\x0e\x32;.pywidevine_license_protocol.ClientIdentification.TokenType:\x06KEYBOX\x12\r\n\x05token\x18\x02 \x01(\x0c\"s\n\tTokenType\x12\n\n\x06KEYBOX\x10\x00\x12\x1a\n\x16\x44RM_DEVICE_CERTIFICATE\x10\x01\x12\"\n\x1eREMOTE_ATTESTATION_CERTIFICATE\x10\x02\x12\x1a\n\x16OEM_DEVICE_CERTIFICATE\x10\x03\"\xbb\x01\n\x1d\x45ncryptedClientIdentification\x12\x13\n\x0bprovider_id\x18\x01 \x01(\t\x12)\n!service_certificate_serial_number\x18\x02 \x01(\x0c\x12\x1b\n\x13\x65ncrypted_client_id\x18\x03 \x01(\x0c\x12\x1e\n\x16\x65ncrypted_client_id_iv\x18\x04 \x01(\x0c\x12\x1d\n\x15\x65ncrypted_privacy_key\x18\x05 \x01(\x0c\"\xba\x07\n\x0e\x44rmCertificate\x12>\n\x04type\x18\x01 \x01(\x0e\x32\x30.pywidevine_license_protocol.DrmCertificate.Type\x12\x15\n\rserial_number\x18\x02 \x01(\x0c\x12\x1d\n\x15\x63reation_time_seconds\x18\x03 \x01(\r\x12\x1f\n\x17\x65xpiration_time_seconds\x18\x0c \x01(\r\x12\x12\n\npublic_key\x18\x04 \x01(\x0c\x12\x11\n\tsystem_id\x18\x05 \x01(\r\x12\"\n\x16test_device_deprecated\x18\x06 \x01(\x08\x42\x02\x18\x01\x12\x13\n\x0bprovider_id\x18\x07 \x01(\t\x12N\n\rservice_types\x18\x08 \x03(\x0e\x32\x37.pywidevine_license_protocol.DrmCertificate.ServiceType\x12M\n\talgorithm\x18\t \x01(\x0e\x32\x35.pywidevine_license_protocol.DrmCertificate.Algorithm:\x03RSA\x12\x0e\n\x06rot_id\x18\n \x01(\x0c\x12Q\n\x0e\x65ncryption_key\x18\x0b \x01(\x0b\x32\x39.pywidevine_license_protocol.DrmCertificate.EncryptionKey\x1ar\n\rEncryptionKey\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12M\n\talgorithm\x18\x02 \x01(\x0e\x32\x35.pywidevine_license_protocol.DrmCertificate.Algorithm:\x03RSA\"L\n\x04Type\x12\x08\n\x04ROOT\x10\x00\x12\x10\n\x0c\x44\x45VICE_MODEL\x10\x01\x12\n\n\x06\x44\x45VICE\x10\x02\x12\x0b\n\x07SERVICE\x10\x03\x12\x0f\n\x0bPROVISIONER\x10\x04\"\x86\x01\n\x0bServiceType\x12\x18\n\x14UNKNOWN_SERVICE_TYPE\x10\x00\x12\x16\n\x12LICENSE_SERVER_SDK\x10\x01\x12\x1c\n\x18LICENSE_SERVER_PROXY_SDK\x10\x02\x12\x14\n\x10PROVISIONING_SDK\x10\x03\x12\x11\n\rCAS_PROXY_SDK\x10\x04\"d\n\tAlgorithm\x12\x15\n\x11UNKNOWN_ALGORITHM\x10\x00\x12\x07\n\x03RSA\x10\x01\x12\x11\n\rECC_SECP256R1\x10\x02\x12\x11\n\rECC_SECP384R1\x10\x03\x12\x11\n\rECC_SECP521R1\x10\x04\"\xce\x01\n\x14SignedDrmCertificate\x12\x17\n\x0f\x64rm_certificate\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x41\n\x06signer\x18\x03 \x01(\x0b\x32\x31.pywidevine_license_protocol.SignedDrmCertificate\x12G\n\x0ehash_algorithm\x18\x04 \x01(\x0e\x32/.pywidevine_license_protocol.HashAlgorithmProto\"\xf6\x05\n\x10WidevinePsshData\x12\x0f\n\x07key_ids\x18\x02 \x03(\x0c\x12\x12\n\ncontent_id\x18\x04 \x01(\x0c\x12\x1b\n\x13\x63rypto_period_index\x18\x07 \x01(\r\x12\x19\n\x11protection_scheme\x18\t \x01(\r\x12\x1d\n\x15\x63rypto_period_seconds\x18\n \x01(\r\x12H\n\x04type\x18\x0b \x01(\x0e\x32\x32.pywidevine_license_protocol.WidevinePsshData.Type:\x06SINGLE\x12\x14\n\x0ckey_sequence\x18\x0c \x01(\r\x12\x11\n\tgroup_ids\x18\r \x03(\x0c\x12P\n\rentitled_keys\x18\x0e \x03(\x0b\x32\x39.pywidevine_license_protocol.WidevinePsshData.EntitledKey\x12\x15\n\rvideo_feature\x18\x0f \x01(\t\x12N\n\talgorithm\x18\x01 \x01(\x0e\x32\x37.pywidevine_license_protocol.WidevinePsshData.AlgorithmB\x02\x18\x01\x12\x14\n\x08provider\x18\x03 \x01(\tB\x02\x18\x01\x12\x16\n\ntrack_type\x18\x05 \x01(\tB\x02\x18\x01\x12\x12\n\x06policy\x18\x06 \x01(\tB\x02\x18\x01\x12\x1b\n\x0fgrouped_license\x18\x08 \x01(\x0c\x42\x02\x18\x01\x1az\n\x0b\x45ntitledKey\x12\x1a\n\x12\x65ntitlement_key_id\x18\x01 \x01(\x0c\x12\x0e\n\x06key_id\x18\x02 \x01(\x0c\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12\n\n\x02iv\x18\x04 \x01(\x0c\x12&\n\x1a\x65ntitlement_key_size_bytes\x18\x05 \x01(\r:\x02\x33\x32\"5\n\x04Type\x12\n\n\x06SINGLE\x10\x00\x12\x0f\n\x0b\x45NTITLEMENT\x10\x01\x12\x10\n\x0c\x45NTITLED_KEY\x10\x02\"(\n\tAlgorithm\x12\x0f\n\x0bUNENCRYPTED\x10\x00\x12\n\n\x06\x41\x45SCTR\x10\x01\"\xd1\x01\n\nFileHashes\x12\x0e\n\x06signer\x18\x01 \x01(\x0c\x12\x45\n\nsignatures\x18\x02 \x03(\x0b\x32\x31.pywidevine_license_protocol.FileHashes.Signature\x1al\n\tSignature\x12\x10\n\x08\x66ilename\x18\x01 \x01(\t\x12\x14\n\x0ctest_signing\x18\x02 \x01(\x08\x12\x12\n\nSHA512Hash\x18\x03 \x01(\x0c\x12\x10\n\x08main_exe\x18\x04 \x01(\x08\x12\x11\n\tsignature\x18\x05 \x01(\x0c*8\n\x0bLicenseType\x12\r\n\tSTREAMING\x10\x01\x12\x0b\n\x07OFFLINE\x10\x02\x12\r\n\tAUTOMATIC\x10\x03*\xd9\x01\n\x1aPlatformVerificationStatus\x12\x17\n\x13PLATFORM_UNVERIFIED\x10\x00\x12\x15\n\x11PLATFORM_TAMPERED\x10\x01\x12\x1e\n\x1aPLATFORM_SOFTWARE_VERIFIED\x10\x02\x12\x1e\n\x1aPLATFORM_HARDWARE_VERIFIED\x10\x03\x12\x1c\n\x18PLATFORM_NO_VERIFICATION\x10\x04\x12-\n)PLATFORM_SECURE_STORAGE_SOFTWARE_VERIFIED\x10\x05*D\n\x0fProtocolVersion\x12\x0f\n\x0bVERSION_2_0\x10\x14\x12\x0f\n\x0bVERSION_2_1\x10\x15\x12\x0f\n\x0bVERSION_2_2\x10\x16*\x86\x01\n\x12HashAlgorithmProto\x12\x1e\n\x1aHASH_ALGORITHM_UNSPECIFIED\x10\x00\x12\x18\n\x14HASH_ALGORITHM_SHA_1\x10\x01\x12\x1a\n\x16HASH_ALGORITHM_SHA_256\x10\x02\x12\x1a\n\x16HASH_ALGORITHM_SHA_384\x10\x03\x42$\n com.rlaphoenix.pywidevine.protosH\x03') - -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'license_protocol_pb2', _globals) -if _descriptor._USE_C_DESCRIPTORS == False: - _globals['DESCRIPTOR']._options = None - _globals['DESCRIPTOR']._serialized_options = b'\n com.rlaphoenix.pywidevine.protosH\003' - _globals['_DRMCERTIFICATE'].fields_by_name['test_device_deprecated']._options = None - _globals['_DRMCERTIFICATE'].fields_by_name['test_device_deprecated']._serialized_options = b'\030\001' - _globals['_WIDEVINEPSSHDATA'].fields_by_name['algorithm']._options = None - _globals['_WIDEVINEPSSHDATA'].fields_by_name['algorithm']._serialized_options = b'\030\001' - _globals['_WIDEVINEPSSHDATA'].fields_by_name['provider']._options = None - _globals['_WIDEVINEPSSHDATA'].fields_by_name['provider']._serialized_options = b'\030\001' - _globals['_WIDEVINEPSSHDATA'].fields_by_name['track_type']._options = None - _globals['_WIDEVINEPSSHDATA'].fields_by_name['track_type']._serialized_options = b'\030\001' - _globals['_WIDEVINEPSSHDATA'].fields_by_name['policy']._options = None - _globals['_WIDEVINEPSSHDATA'].fields_by_name['policy']._serialized_options = b'\030\001' - _globals['_WIDEVINEPSSHDATA'].fields_by_name['grouped_license']._options = None - _globals['_WIDEVINEPSSHDATA'].fields_by_name['grouped_license']._serialized_options = b'\030\001' - _globals['_LICENSETYPE']._serialized_start=10442 - _globals['_LICENSETYPE']._serialized_end=10498 - _globals['_PLATFORMVERIFICATIONSTATUS']._serialized_start=10501 - _globals['_PLATFORMVERIFICATIONSTATUS']._serialized_end=10718 - _globals['_PROTOCOLVERSION']._serialized_start=10720 - _globals['_PROTOCOLVERSION']._serialized_end=10788 - _globals['_HASHALGORITHMPROTO']._serialized_start=10791 - _globals['_HASHALGORITHMPROTO']._serialized_end=10925 - _globals['_LICENSEIDENTIFICATION']._serialized_start=56 - _globals['_LICENSEIDENTIFICATION']._serialized_end=245 - _globals['_LICENSE']._serialized_start=248 - _globals['_LICENSE']._serialized_end=3433 - _globals['_LICENSE_POLICY']._serialized_start=764 - _globals['_LICENSE_POLICY']._serialized_end=1322 - _globals['_LICENSE_KEYCONTAINER']._serialized_start=1325 - _globals['_LICENSE_KEYCONTAINER']._serialized_end=3433 - _globals['_LICENSE_KEYCONTAINER_KEYCONTROL']._serialized_start=2128 - _globals['_LICENSE_KEYCONTAINER_KEYCONTROL']._serialized_end=2179 - _globals['_LICENSE_KEYCONTAINER_OUTPUTPROTECTION']._serialized_start=2182 - _globals['_LICENSE_KEYCONTAINER_OUTPUTPROTECTION']._serialized_end=2850 - _globals['_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_HDCP']._serialized_start=2604 - _globals['_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_HDCP']._serialized_end=2725 - _globals['_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS']._serialized_start=2727 - _globals['_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_CGMS']._serialized_end=2794 - _globals['_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_HDCPSRMRULE']._serialized_start=2796 - _globals['_LICENSE_KEYCONTAINER_OUTPUTPROTECTION_HDCPSRMRULE']._serialized_end=2850 - _globals['_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT']._serialized_start=2853 - _globals['_LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT']._serialized_end=3039 - _globals['_LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS']._serialized_start=3042 - _globals['_LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS']._serialized_end=3199 - _globals['_LICENSE_KEYCONTAINER_KEYTYPE']._serialized_start=3201 - _globals['_LICENSE_KEYCONTAINER_KEYTYPE']._serialized_end=3309 - _globals['_LICENSE_KEYCONTAINER_SECURITYLEVEL']._serialized_start=3311 - _globals['_LICENSE_KEYCONTAINER_SECURITYLEVEL']._serialized_end=3433 - _globals['_LICENSEREQUEST']._serialized_start=3436 - _globals['_LICENSEREQUEST']._serialized_end=5161 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION']._serialized_start=3944 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION']._serialized_end=5111 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_WIDEVINEPSSHDATA']._serialized_start=4391 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_WIDEVINEPSSHDATA']._serialized_end=4512 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBMKEYID']._serialized_start=4514 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_WEBMKEYID']._serialized_end=4625 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE']._serialized_start=4628 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE']._serialized_end=4818 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_INITDATA']._serialized_start=4821 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_INITDATA']._serialized_end=5089 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_INITDATA_INITDATATYPE']._serialized_start=5055 - _globals['_LICENSEREQUEST_CONTENTIDENTIFICATION_INITDATA_INITDATATYPE']._serialized_end=5089 - _globals['_LICENSEREQUEST_REQUESTTYPE']._serialized_start=5113 - _globals['_LICENSEREQUEST_REQUESTTYPE']._serialized_end=5161 - _globals['_METRICDATA']._serialized_start=5164 - _globals['_METRICDATA']._serialized_end=5407 - _globals['_METRICDATA_TYPEVALUE']._serialized_start=5270 - _globals['_METRICDATA_TYPEVALUE']._serialized_end=5365 - _globals['_METRICDATA_METRICTYPE']._serialized_start=5367 - _globals['_METRICDATA_METRICTYPE']._serialized_end=5407 - _globals['_VERSIONINFO']._serialized_start=5409 - _globals['_VERSIONINFO']._serialized_end=5484 - _globals['_SIGNEDMESSAGE']._serialized_start=5487 - _globals['_SIGNEDMESSAGE']._serialized_end=6245 - _globals['_SIGNEDMESSAGE_MESSAGETYPE']._serialized_start=5924 - _globals['_SIGNEDMESSAGE_MESSAGETYPE']._serialized_end=6160 - _globals['_SIGNEDMESSAGE_SESSIONKEYTYPE']._serialized_start=6162 - _globals['_SIGNEDMESSAGE_SESSIONKEYTYPE']._serialized_end=6245 - _globals['_CLIENTIDENTIFICATION']._serialized_start=6248 - _globals['_CLIENTIDENTIFICATION']._serialized_end=8111 - _globals['_CLIENTIDENTIFICATION_NAMEVALUE']._serialized_start=6722 - _globals['_CLIENTIDENTIFICATION_NAMEVALUE']._serialized_end=6762 - _globals['_CLIENTIDENTIFICATION_CLIENTCAPABILITIES']._serialized_start=6765 - _globals['_CLIENTIDENTIFICATION_CLIENTCAPABILITIES']._serialized_end=7875 - _globals['_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION']._serialized_start=7496 - _globals['_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_HDCPVERSION']._serialized_end=7624 - _globals['_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_CERTIFICATEKEYTYPE']._serialized_start=7626 - _globals['_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_CERTIFICATEKEYTYPE']._serialized_end=7731 - _globals['_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_ANALOGOUTPUTCAPABILITIES']._serialized_start=7734 - _globals['_CLIENTIDENTIFICATION_CLIENTCAPABILITIES_ANALOGOUTPUTCAPABILITIES']._serialized_end=7875 - _globals['_CLIENTIDENTIFICATION_CLIENTCREDENTIALS']._serialized_start=7877 - _globals['_CLIENTIDENTIFICATION_CLIENTCREDENTIALS']._serialized_end=7994 - _globals['_CLIENTIDENTIFICATION_TOKENTYPE']._serialized_start=7996 - _globals['_CLIENTIDENTIFICATION_TOKENTYPE']._serialized_end=8111 - _globals['_ENCRYPTEDCLIENTIDENTIFICATION']._serialized_start=8114 - _globals['_ENCRYPTEDCLIENTIDENTIFICATION']._serialized_end=8301 - _globals['_DRMCERTIFICATE']._serialized_start=8304 - _globals['_DRMCERTIFICATE']._serialized_end=9258 - _globals['_DRMCERTIFICATE_ENCRYPTIONKEY']._serialized_start=8827 - _globals['_DRMCERTIFICATE_ENCRYPTIONKEY']._serialized_end=8941 - _globals['_DRMCERTIFICATE_TYPE']._serialized_start=8943 - _globals['_DRMCERTIFICATE_TYPE']._serialized_end=9019 - _globals['_DRMCERTIFICATE_SERVICETYPE']._serialized_start=9022 - _globals['_DRMCERTIFICATE_SERVICETYPE']._serialized_end=9156 - _globals['_DRMCERTIFICATE_ALGORITHM']._serialized_start=9158 - _globals['_DRMCERTIFICATE_ALGORITHM']._serialized_end=9258 - _globals['_SIGNEDDRMCERTIFICATE']._serialized_start=9261 - _globals['_SIGNEDDRMCERTIFICATE']._serialized_end=9467 - _globals['_WIDEVINEPSSHDATA']._serialized_start=9470 - _globals['_WIDEVINEPSSHDATA']._serialized_end=10228 - _globals['_WIDEVINEPSSHDATA_ENTITLEDKEY']._serialized_start=10009 - _globals['_WIDEVINEPSSHDATA_ENTITLEDKEY']._serialized_end=10131 - _globals['_WIDEVINEPSSHDATA_TYPE']._serialized_start=10133 - _globals['_WIDEVINEPSSHDATA_TYPE']._serialized_end=10186 - _globals['_WIDEVINEPSSHDATA_ALGORITHM']._serialized_start=10188 - _globals['_WIDEVINEPSSHDATA_ALGORITHM']._serialized_end=10228 - _globals['_FILEHASHES']._serialized_start=10231 - _globals['_FILEHASHES']._serialized_end=10440 - _globals['_FILEHASHES_SIGNATURE']._serialized_start=10332 - _globals['_FILEHASHES_SIGNATURE']._serialized_end=10440 -# @@protoc_insertion_point(module_scope) diff --git a/scripts/pywidevine/pywidevine/license_protocol_pb2.pyi b/scripts/pywidevine/pywidevine/license_protocol_pb2.pyi deleted file mode 100644 index 44f543e..0000000 --- a/scripts/pywidevine/pywidevine/license_protocol_pb2.pyi +++ /dev/null @@ -1,607 +0,0 @@ -# mypy: ignore-errors - -from google.protobuf.internal import containers as _containers -from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union - -AUTOMATIC: LicenseType -DESCRIPTOR: _descriptor.FileDescriptor -HASH_ALGORITHM_SHA_1: HashAlgorithmProto -HASH_ALGORITHM_SHA_256: HashAlgorithmProto -HASH_ALGORITHM_SHA_384: HashAlgorithmProto -HASH_ALGORITHM_UNSPECIFIED: HashAlgorithmProto -OFFLINE: LicenseType -PLATFORM_HARDWARE_VERIFIED: PlatformVerificationStatus -PLATFORM_NO_VERIFICATION: PlatformVerificationStatus -PLATFORM_SECURE_STORAGE_SOFTWARE_VERIFIED: PlatformVerificationStatus -PLATFORM_SOFTWARE_VERIFIED: PlatformVerificationStatus -PLATFORM_TAMPERED: PlatformVerificationStatus -PLATFORM_UNVERIFIED: PlatformVerificationStatus -STREAMING: LicenseType -VERSION_2_0: ProtocolVersion -VERSION_2_1: ProtocolVersion -VERSION_2_2: ProtocolVersion - -class ClientIdentification(_message.Message): - __slots__ = ["client_capabilities", "client_info", "device_credentials", "license_counter", "provider_client_token", "token", "type", "vmp_data"] - class TokenType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class ClientCapabilities(_message.Message): - __slots__ = ["analog_output_capabilities", "anti_rollback_usage_table", "can_disable_analog_output", "can_update_srm", "client_token", "max_hdcp_version", "oem_crypto_api_version", "resource_rating_tier", "session_token", "srm_version", "supported_certificate_key_type", "video_resolution_constraints"] - class AnalogOutputCapabilities(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class CertificateKeyType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class HdcpVersion(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - ANALOG_OUTPUT_CAPABILITIES_FIELD_NUMBER: _ClassVar[int] - ANALOG_OUTPUT_NONE: ClientIdentification.ClientCapabilities.AnalogOutputCapabilities - ANALOG_OUTPUT_SUPPORTED: ClientIdentification.ClientCapabilities.AnalogOutputCapabilities - ANALOG_OUTPUT_SUPPORTS_CGMS_A: ClientIdentification.ClientCapabilities.AnalogOutputCapabilities - ANALOG_OUTPUT_UNKNOWN: ClientIdentification.ClientCapabilities.AnalogOutputCapabilities - ANTI_ROLLBACK_USAGE_TABLE_FIELD_NUMBER: _ClassVar[int] - CAN_DISABLE_ANALOG_OUTPUT_FIELD_NUMBER: _ClassVar[int] - CAN_UPDATE_SRM_FIELD_NUMBER: _ClassVar[int] - CLIENT_TOKEN_FIELD_NUMBER: _ClassVar[int] - ECC_SECP256R1: ClientIdentification.ClientCapabilities.CertificateKeyType - ECC_SECP384R1: ClientIdentification.ClientCapabilities.CertificateKeyType - ECC_SECP521R1: ClientIdentification.ClientCapabilities.CertificateKeyType - HDCP_NONE: ClientIdentification.ClientCapabilities.HdcpVersion - HDCP_NO_DIGITAL_OUTPUT: ClientIdentification.ClientCapabilities.HdcpVersion - HDCP_V1: ClientIdentification.ClientCapabilities.HdcpVersion - HDCP_V2: ClientIdentification.ClientCapabilities.HdcpVersion - HDCP_V2_1: ClientIdentification.ClientCapabilities.HdcpVersion - HDCP_V2_2: ClientIdentification.ClientCapabilities.HdcpVersion - HDCP_V2_3: ClientIdentification.ClientCapabilities.HdcpVersion - MAX_HDCP_VERSION_FIELD_NUMBER: _ClassVar[int] - OEM_CRYPTO_API_VERSION_FIELD_NUMBER: _ClassVar[int] - RESOURCE_RATING_TIER_FIELD_NUMBER: _ClassVar[int] - RSA_2048: ClientIdentification.ClientCapabilities.CertificateKeyType - RSA_3072: ClientIdentification.ClientCapabilities.CertificateKeyType - SESSION_TOKEN_FIELD_NUMBER: _ClassVar[int] - SRM_VERSION_FIELD_NUMBER: _ClassVar[int] - SUPPORTED_CERTIFICATE_KEY_TYPE_FIELD_NUMBER: _ClassVar[int] - VIDEO_RESOLUTION_CONSTRAINTS_FIELD_NUMBER: _ClassVar[int] - analog_output_capabilities: ClientIdentification.ClientCapabilities.AnalogOutputCapabilities - anti_rollback_usage_table: bool - can_disable_analog_output: bool - can_update_srm: bool - client_token: bool - max_hdcp_version: ClientIdentification.ClientCapabilities.HdcpVersion - oem_crypto_api_version: int - resource_rating_tier: int - session_token: bool - srm_version: int - supported_certificate_key_type: _containers.RepeatedScalarFieldContainer[ClientIdentification.ClientCapabilities.CertificateKeyType] - video_resolution_constraints: bool - def __init__(self, client_token: bool = ..., session_token: bool = ..., video_resolution_constraints: bool = ..., max_hdcp_version: _Optional[_Union[ClientIdentification.ClientCapabilities.HdcpVersion, str]] = ..., oem_crypto_api_version: _Optional[int] = ..., anti_rollback_usage_table: bool = ..., srm_version: _Optional[int] = ..., can_update_srm: bool = ..., supported_certificate_key_type: _Optional[_Iterable[_Union[ClientIdentification.ClientCapabilities.CertificateKeyType, str]]] = ..., analog_output_capabilities: _Optional[_Union[ClientIdentification.ClientCapabilities.AnalogOutputCapabilities, str]] = ..., can_disable_analog_output: bool = ..., resource_rating_tier: _Optional[int] = ...) -> None: ... - class ClientCredentials(_message.Message): - __slots__ = ["token", "type"] - TOKEN_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - token: bytes - type: ClientIdentification.TokenType - def __init__(self, type: _Optional[_Union[ClientIdentification.TokenType, str]] = ..., token: _Optional[bytes] = ...) -> None: ... - class NameValue(_message.Message): - __slots__ = ["name", "value"] - NAME_FIELD_NUMBER: _ClassVar[int] - VALUE_FIELD_NUMBER: _ClassVar[int] - name: str - value: str - def __init__(self, name: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... - CLIENT_CAPABILITIES_FIELD_NUMBER: _ClassVar[int] - CLIENT_INFO_FIELD_NUMBER: _ClassVar[int] - DEVICE_CREDENTIALS_FIELD_NUMBER: _ClassVar[int] - DRM_DEVICE_CERTIFICATE: ClientIdentification.TokenType - KEYBOX: ClientIdentification.TokenType - LICENSE_COUNTER_FIELD_NUMBER: _ClassVar[int] - OEM_DEVICE_CERTIFICATE: ClientIdentification.TokenType - PROVIDER_CLIENT_TOKEN_FIELD_NUMBER: _ClassVar[int] - REMOTE_ATTESTATION_CERTIFICATE: ClientIdentification.TokenType - TOKEN_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - VMP_DATA_FIELD_NUMBER: _ClassVar[int] - client_capabilities: ClientIdentification.ClientCapabilities - client_info: _containers.RepeatedCompositeFieldContainer[ClientIdentification.NameValue] - device_credentials: _containers.RepeatedCompositeFieldContainer[ClientIdentification.ClientCredentials] - license_counter: int - provider_client_token: bytes - token: bytes - type: ClientIdentification.TokenType - vmp_data: bytes - def __init__(self, type: _Optional[_Union[ClientIdentification.TokenType, str]] = ..., token: _Optional[bytes] = ..., client_info: _Optional[_Iterable[_Union[ClientIdentification.NameValue, _Mapping]]] = ..., provider_client_token: _Optional[bytes] = ..., license_counter: _Optional[int] = ..., client_capabilities: _Optional[_Union[ClientIdentification.ClientCapabilities, _Mapping]] = ..., vmp_data: _Optional[bytes] = ..., device_credentials: _Optional[_Iterable[_Union[ClientIdentification.ClientCredentials, _Mapping]]] = ...) -> None: ... - -class DrmCertificate(_message.Message): - __slots__ = ["algorithm", "creation_time_seconds", "encryption_key", "expiration_time_seconds", "provider_id", "public_key", "rot_id", "serial_number", "service_types", "system_id", "test_device_deprecated", "type"] - class Algorithm(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class ServiceType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class Type(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class EncryptionKey(_message.Message): - __slots__ = ["algorithm", "public_key"] - ALGORITHM_FIELD_NUMBER: _ClassVar[int] - PUBLIC_KEY_FIELD_NUMBER: _ClassVar[int] - algorithm: DrmCertificate.Algorithm - public_key: bytes - def __init__(self, public_key: _Optional[bytes] = ..., algorithm: _Optional[_Union[DrmCertificate.Algorithm, str]] = ...) -> None: ... - ALGORITHM_FIELD_NUMBER: _ClassVar[int] - CAS_PROXY_SDK: DrmCertificate.ServiceType - CREATION_TIME_SECONDS_FIELD_NUMBER: _ClassVar[int] - DEVICE: DrmCertificate.Type - DEVICE_MODEL: DrmCertificate.Type - ECC_SECP256R1: DrmCertificate.Algorithm - ECC_SECP384R1: DrmCertificate.Algorithm - ECC_SECP521R1: DrmCertificate.Algorithm - ENCRYPTION_KEY_FIELD_NUMBER: _ClassVar[int] - EXPIRATION_TIME_SECONDS_FIELD_NUMBER: _ClassVar[int] - LICENSE_SERVER_PROXY_SDK: DrmCertificate.ServiceType - LICENSE_SERVER_SDK: DrmCertificate.ServiceType - PROVIDER_ID_FIELD_NUMBER: _ClassVar[int] - PROVISIONER: DrmCertificate.Type - PROVISIONING_SDK: DrmCertificate.ServiceType - PUBLIC_KEY_FIELD_NUMBER: _ClassVar[int] - ROOT: DrmCertificate.Type - ROT_ID_FIELD_NUMBER: _ClassVar[int] - RSA: DrmCertificate.Algorithm - SERIAL_NUMBER_FIELD_NUMBER: _ClassVar[int] - SERVICE: DrmCertificate.Type - SERVICE_TYPES_FIELD_NUMBER: _ClassVar[int] - SYSTEM_ID_FIELD_NUMBER: _ClassVar[int] - TEST_DEVICE_DEPRECATED_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - UNKNOWN_ALGORITHM: DrmCertificate.Algorithm - UNKNOWN_SERVICE_TYPE: DrmCertificate.ServiceType - algorithm: DrmCertificate.Algorithm - creation_time_seconds: int - encryption_key: DrmCertificate.EncryptionKey - expiration_time_seconds: int - provider_id: str - public_key: bytes - rot_id: bytes - serial_number: bytes - service_types: _containers.RepeatedScalarFieldContainer[DrmCertificate.ServiceType] - system_id: int - test_device_deprecated: bool - type: DrmCertificate.Type - def __init__(self, type: _Optional[_Union[DrmCertificate.Type, str]] = ..., serial_number: _Optional[bytes] = ..., creation_time_seconds: _Optional[int] = ..., expiration_time_seconds: _Optional[int] = ..., public_key: _Optional[bytes] = ..., system_id: _Optional[int] = ..., test_device_deprecated: bool = ..., provider_id: _Optional[str] = ..., service_types: _Optional[_Iterable[_Union[DrmCertificate.ServiceType, str]]] = ..., algorithm: _Optional[_Union[DrmCertificate.Algorithm, str]] = ..., rot_id: _Optional[bytes] = ..., encryption_key: _Optional[_Union[DrmCertificate.EncryptionKey, _Mapping]] = ...) -> None: ... - -class EncryptedClientIdentification(_message.Message): - __slots__ = ["encrypted_client_id", "encrypted_client_id_iv", "encrypted_privacy_key", "provider_id", "service_certificate_serial_number"] - ENCRYPTED_CLIENT_ID_FIELD_NUMBER: _ClassVar[int] - ENCRYPTED_CLIENT_ID_IV_FIELD_NUMBER: _ClassVar[int] - ENCRYPTED_PRIVACY_KEY_FIELD_NUMBER: _ClassVar[int] - PROVIDER_ID_FIELD_NUMBER: _ClassVar[int] - SERVICE_CERTIFICATE_SERIAL_NUMBER_FIELD_NUMBER: _ClassVar[int] - encrypted_client_id: bytes - encrypted_client_id_iv: bytes - encrypted_privacy_key: bytes - provider_id: str - service_certificate_serial_number: bytes - def __init__(self, provider_id: _Optional[str] = ..., service_certificate_serial_number: _Optional[bytes] = ..., encrypted_client_id: _Optional[bytes] = ..., encrypted_client_id_iv: _Optional[bytes] = ..., encrypted_privacy_key: _Optional[bytes] = ...) -> None: ... - -class FileHashes(_message.Message): - __slots__ = ["signatures", "signer"] - class Signature(_message.Message): - __slots__ = ["SHA512Hash", "filename", "main_exe", "signature", "test_signing"] - FILENAME_FIELD_NUMBER: _ClassVar[int] - MAIN_EXE_FIELD_NUMBER: _ClassVar[int] - SHA512HASH_FIELD_NUMBER: _ClassVar[int] - SHA512Hash: bytes - SIGNATURE_FIELD_NUMBER: _ClassVar[int] - TEST_SIGNING_FIELD_NUMBER: _ClassVar[int] - filename: str - main_exe: bool - signature: bytes - test_signing: bool - def __init__(self, filename: _Optional[str] = ..., test_signing: bool = ..., SHA512Hash: _Optional[bytes] = ..., main_exe: bool = ..., signature: _Optional[bytes] = ...) -> None: ... - SIGNATURES_FIELD_NUMBER: _ClassVar[int] - SIGNER_FIELD_NUMBER: _ClassVar[int] - signatures: _containers.RepeatedCompositeFieldContainer[FileHashes.Signature] - signer: bytes - def __init__(self, signer: _Optional[bytes] = ..., signatures: _Optional[_Iterable[_Union[FileHashes.Signature, _Mapping]]] = ...) -> None: ... - -class License(_message.Message): - __slots__ = ["group_ids", "id", "key", "license_start_time", "platform_verification_status", "policy", "protection_scheme", "provider_client_token", "remote_attestation_verified", "srm_requirement", "srm_update"] - class KeyContainer(_message.Message): - __slots__ = ["anti_rollback_usage_table", "id", "iv", "key", "key_control", "level", "operator_session_key_permissions", "requested_protection", "required_protection", "track_label", "type", "video_resolution_constraints"] - class KeyType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class SecurityLevel(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class KeyControl(_message.Message): - __slots__ = ["iv", "key_control_block"] - IV_FIELD_NUMBER: _ClassVar[int] - KEY_CONTROL_BLOCK_FIELD_NUMBER: _ClassVar[int] - iv: bytes - key_control_block: bytes - def __init__(self, key_control_block: _Optional[bytes] = ..., iv: _Optional[bytes] = ...) -> None: ... - class OperatorSessionKeyPermissions(_message.Message): - __slots__ = ["allow_decrypt", "allow_encrypt", "allow_sign", "allow_signature_verify"] - ALLOW_DECRYPT_FIELD_NUMBER: _ClassVar[int] - ALLOW_ENCRYPT_FIELD_NUMBER: _ClassVar[int] - ALLOW_SIGNATURE_VERIFY_FIELD_NUMBER: _ClassVar[int] - ALLOW_SIGN_FIELD_NUMBER: _ClassVar[int] - allow_decrypt: bool - allow_encrypt: bool - allow_sign: bool - allow_signature_verify: bool - def __init__(self, allow_encrypt: bool = ..., allow_decrypt: bool = ..., allow_sign: bool = ..., allow_signature_verify: bool = ...) -> None: ... - class OutputProtection(_message.Message): - __slots__ = ["cgms_flags", "disable_analog_output", "disable_digital_output", "hdcp", "hdcp_srm_rule"] - class CGMS(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class HDCP(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class HdcpSrmRule(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - CGMS_FLAGS_FIELD_NUMBER: _ClassVar[int] - CGMS_NONE: License.KeyContainer.OutputProtection.CGMS - COPY_FREE: License.KeyContainer.OutputProtection.CGMS - COPY_NEVER: License.KeyContainer.OutputProtection.CGMS - COPY_ONCE: License.KeyContainer.OutputProtection.CGMS - CURRENT_SRM: License.KeyContainer.OutputProtection.HdcpSrmRule - DISABLE_ANALOG_OUTPUT_FIELD_NUMBER: _ClassVar[int] - DISABLE_DIGITAL_OUTPUT_FIELD_NUMBER: _ClassVar[int] - HDCP_FIELD_NUMBER: _ClassVar[int] - HDCP_NONE: License.KeyContainer.OutputProtection.HDCP - HDCP_NO_DIGITAL_OUTPUT: License.KeyContainer.OutputProtection.HDCP - HDCP_SRM_RULE_FIELD_NUMBER: _ClassVar[int] - HDCP_SRM_RULE_NONE: License.KeyContainer.OutputProtection.HdcpSrmRule - HDCP_V1: License.KeyContainer.OutputProtection.HDCP - HDCP_V2: License.KeyContainer.OutputProtection.HDCP - HDCP_V2_1: License.KeyContainer.OutputProtection.HDCP - HDCP_V2_2: License.KeyContainer.OutputProtection.HDCP - HDCP_V2_3: License.KeyContainer.OutputProtection.HDCP - cgms_flags: License.KeyContainer.OutputProtection.CGMS - disable_analog_output: bool - disable_digital_output: bool - hdcp: License.KeyContainer.OutputProtection.HDCP - hdcp_srm_rule: License.KeyContainer.OutputProtection.HdcpSrmRule - def __init__(self, hdcp: _Optional[_Union[License.KeyContainer.OutputProtection.HDCP, str]] = ..., cgms_flags: _Optional[_Union[License.KeyContainer.OutputProtection.CGMS, str]] = ..., hdcp_srm_rule: _Optional[_Union[License.KeyContainer.OutputProtection.HdcpSrmRule, str]] = ..., disable_analog_output: bool = ..., disable_digital_output: bool = ...) -> None: ... - class VideoResolutionConstraint(_message.Message): - __slots__ = ["max_resolution_pixels", "min_resolution_pixels", "required_protection"] - MAX_RESOLUTION_PIXELS_FIELD_NUMBER: _ClassVar[int] - MIN_RESOLUTION_PIXELS_FIELD_NUMBER: _ClassVar[int] - REQUIRED_PROTECTION_FIELD_NUMBER: _ClassVar[int] - max_resolution_pixels: int - min_resolution_pixels: int - required_protection: License.KeyContainer.OutputProtection - def __init__(self, min_resolution_pixels: _Optional[int] = ..., max_resolution_pixels: _Optional[int] = ..., required_protection: _Optional[_Union[License.KeyContainer.OutputProtection, _Mapping]] = ...) -> None: ... - ANTI_ROLLBACK_USAGE_TABLE_FIELD_NUMBER: _ClassVar[int] - CONTENT: License.KeyContainer.KeyType - ENTITLEMENT: License.KeyContainer.KeyType - HW_SECURE_ALL: License.KeyContainer.SecurityLevel - HW_SECURE_CRYPTO: License.KeyContainer.SecurityLevel - HW_SECURE_DECODE: License.KeyContainer.SecurityLevel - ID_FIELD_NUMBER: _ClassVar[int] - IV_FIELD_NUMBER: _ClassVar[int] - KEY_CONTROL: License.KeyContainer.KeyType - KEY_CONTROL_FIELD_NUMBER: _ClassVar[int] - KEY_FIELD_NUMBER: _ClassVar[int] - LEVEL_FIELD_NUMBER: _ClassVar[int] - OEM_CONTENT: License.KeyContainer.KeyType - OPERATOR_SESSION: License.KeyContainer.KeyType - OPERATOR_SESSION_KEY_PERMISSIONS_FIELD_NUMBER: _ClassVar[int] - REQUESTED_PROTECTION_FIELD_NUMBER: _ClassVar[int] - REQUIRED_PROTECTION_FIELD_NUMBER: _ClassVar[int] - SIGNING: License.KeyContainer.KeyType - SW_SECURE_CRYPTO: License.KeyContainer.SecurityLevel - SW_SECURE_DECODE: License.KeyContainer.SecurityLevel - TRACK_LABEL_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - VIDEO_RESOLUTION_CONSTRAINTS_FIELD_NUMBER: _ClassVar[int] - anti_rollback_usage_table: bool - id: bytes - iv: bytes - key: bytes - key_control: License.KeyContainer.KeyControl - level: License.KeyContainer.SecurityLevel - operator_session_key_permissions: License.KeyContainer.OperatorSessionKeyPermissions - requested_protection: License.KeyContainer.OutputProtection - required_protection: License.KeyContainer.OutputProtection - track_label: str - type: License.KeyContainer.KeyType - video_resolution_constraints: _containers.RepeatedCompositeFieldContainer[License.KeyContainer.VideoResolutionConstraint] - def __init__(self, id: _Optional[bytes] = ..., iv: _Optional[bytes] = ..., key: _Optional[bytes] = ..., type: _Optional[_Union[License.KeyContainer.KeyType, str]] = ..., level: _Optional[_Union[License.KeyContainer.SecurityLevel, str]] = ..., required_protection: _Optional[_Union[License.KeyContainer.OutputProtection, _Mapping]] = ..., requested_protection: _Optional[_Union[License.KeyContainer.OutputProtection, _Mapping]] = ..., key_control: _Optional[_Union[License.KeyContainer.KeyControl, _Mapping]] = ..., operator_session_key_permissions: _Optional[_Union[License.KeyContainer.OperatorSessionKeyPermissions, _Mapping]] = ..., video_resolution_constraints: _Optional[_Iterable[_Union[License.KeyContainer.VideoResolutionConstraint, _Mapping]]] = ..., anti_rollback_usage_table: bool = ..., track_label: _Optional[str] = ...) -> None: ... - class Policy(_message.Message): - __slots__ = ["always_include_client_id", "can_persist", "can_play", "can_renew", "license_duration_seconds", "play_start_grace_period_seconds", "playback_duration_seconds", "renew_with_usage", "renewal_delay_seconds", "renewal_recovery_duration_seconds", "renewal_retry_interval_seconds", "renewal_server_url", "rental_duration_seconds", "soft_enforce_playback_duration", "soft_enforce_rental_duration"] - ALWAYS_INCLUDE_CLIENT_ID_FIELD_NUMBER: _ClassVar[int] - CAN_PERSIST_FIELD_NUMBER: _ClassVar[int] - CAN_PLAY_FIELD_NUMBER: _ClassVar[int] - CAN_RENEW_FIELD_NUMBER: _ClassVar[int] - LICENSE_DURATION_SECONDS_FIELD_NUMBER: _ClassVar[int] - PLAYBACK_DURATION_SECONDS_FIELD_NUMBER: _ClassVar[int] - PLAY_START_GRACE_PERIOD_SECONDS_FIELD_NUMBER: _ClassVar[int] - RENEWAL_DELAY_SECONDS_FIELD_NUMBER: _ClassVar[int] - RENEWAL_RECOVERY_DURATION_SECONDS_FIELD_NUMBER: _ClassVar[int] - RENEWAL_RETRY_INTERVAL_SECONDS_FIELD_NUMBER: _ClassVar[int] - RENEWAL_SERVER_URL_FIELD_NUMBER: _ClassVar[int] - RENEW_WITH_USAGE_FIELD_NUMBER: _ClassVar[int] - RENTAL_DURATION_SECONDS_FIELD_NUMBER: _ClassVar[int] - SOFT_ENFORCE_PLAYBACK_DURATION_FIELD_NUMBER: _ClassVar[int] - SOFT_ENFORCE_RENTAL_DURATION_FIELD_NUMBER: _ClassVar[int] - always_include_client_id: bool - can_persist: bool - can_play: bool - can_renew: bool - license_duration_seconds: int - play_start_grace_period_seconds: int - playback_duration_seconds: int - renew_with_usage: bool - renewal_delay_seconds: int - renewal_recovery_duration_seconds: int - renewal_retry_interval_seconds: int - renewal_server_url: str - rental_duration_seconds: int - soft_enforce_playback_duration: bool - soft_enforce_rental_duration: bool - def __init__(self, can_play: bool = ..., can_persist: bool = ..., can_renew: bool = ..., rental_duration_seconds: _Optional[int] = ..., playback_duration_seconds: _Optional[int] = ..., license_duration_seconds: _Optional[int] = ..., renewal_recovery_duration_seconds: _Optional[int] = ..., renewal_server_url: _Optional[str] = ..., renewal_delay_seconds: _Optional[int] = ..., renewal_retry_interval_seconds: _Optional[int] = ..., renew_with_usage: bool = ..., always_include_client_id: bool = ..., play_start_grace_period_seconds: _Optional[int] = ..., soft_enforce_playback_duration: bool = ..., soft_enforce_rental_duration: bool = ...) -> None: ... - GROUP_IDS_FIELD_NUMBER: _ClassVar[int] - ID_FIELD_NUMBER: _ClassVar[int] - KEY_FIELD_NUMBER: _ClassVar[int] - LICENSE_START_TIME_FIELD_NUMBER: _ClassVar[int] - PLATFORM_VERIFICATION_STATUS_FIELD_NUMBER: _ClassVar[int] - POLICY_FIELD_NUMBER: _ClassVar[int] - PROTECTION_SCHEME_FIELD_NUMBER: _ClassVar[int] - PROVIDER_CLIENT_TOKEN_FIELD_NUMBER: _ClassVar[int] - REMOTE_ATTESTATION_VERIFIED_FIELD_NUMBER: _ClassVar[int] - SRM_REQUIREMENT_FIELD_NUMBER: _ClassVar[int] - SRM_UPDATE_FIELD_NUMBER: _ClassVar[int] - group_ids: _containers.RepeatedScalarFieldContainer[bytes] - id: LicenseIdentification - key: _containers.RepeatedCompositeFieldContainer[License.KeyContainer] - license_start_time: int - platform_verification_status: PlatformVerificationStatus - policy: License.Policy - protection_scheme: int - provider_client_token: bytes - remote_attestation_verified: bool - srm_requirement: bytes - srm_update: bytes - def __init__(self, id: _Optional[_Union[LicenseIdentification, _Mapping]] = ..., policy: _Optional[_Union[License.Policy, _Mapping]] = ..., key: _Optional[_Iterable[_Union[License.KeyContainer, _Mapping]]] = ..., license_start_time: _Optional[int] = ..., remote_attestation_verified: bool = ..., provider_client_token: _Optional[bytes] = ..., protection_scheme: _Optional[int] = ..., srm_requirement: _Optional[bytes] = ..., srm_update: _Optional[bytes] = ..., platform_verification_status: _Optional[_Union[PlatformVerificationStatus, str]] = ..., group_ids: _Optional[_Iterable[bytes]] = ...) -> None: ... - -class LicenseIdentification(_message.Message): - __slots__ = ["provider_session_token", "purchase_id", "request_id", "session_id", "type", "version"] - PROVIDER_SESSION_TOKEN_FIELD_NUMBER: _ClassVar[int] - PURCHASE_ID_FIELD_NUMBER: _ClassVar[int] - REQUEST_ID_FIELD_NUMBER: _ClassVar[int] - SESSION_ID_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - VERSION_FIELD_NUMBER: _ClassVar[int] - provider_session_token: bytes - purchase_id: bytes - request_id: bytes - session_id: bytes - type: LicenseType - version: int - def __init__(self, request_id: _Optional[bytes] = ..., session_id: _Optional[bytes] = ..., purchase_id: _Optional[bytes] = ..., type: _Optional[_Union[LicenseType, str]] = ..., version: _Optional[int] = ..., provider_session_token: _Optional[bytes] = ...) -> None: ... - -class LicenseRequest(_message.Message): - __slots__ = ["client_id", "content_id", "encrypted_client_id", "key_control_nonce", "key_control_nonce_deprecated", "protocol_version", "request_time", "type"] - class RequestType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class ContentIdentification(_message.Message): - __slots__ = ["existing_license", "init_data", "webm_key_id", "widevine_pssh_data"] - class ExistingLicense(_message.Message): - __slots__ = ["license_id", "seconds_since_last_played", "seconds_since_started", "session_usage_table_entry"] - LICENSE_ID_FIELD_NUMBER: _ClassVar[int] - SECONDS_SINCE_LAST_PLAYED_FIELD_NUMBER: _ClassVar[int] - SECONDS_SINCE_STARTED_FIELD_NUMBER: _ClassVar[int] - SESSION_USAGE_TABLE_ENTRY_FIELD_NUMBER: _ClassVar[int] - license_id: LicenseIdentification - seconds_since_last_played: int - seconds_since_started: int - session_usage_table_entry: bytes - def __init__(self, license_id: _Optional[_Union[LicenseIdentification, _Mapping]] = ..., seconds_since_started: _Optional[int] = ..., seconds_since_last_played: _Optional[int] = ..., session_usage_table_entry: _Optional[bytes] = ...) -> None: ... - class InitData(_message.Message): - __slots__ = ["init_data", "init_data_type", "license_type", "request_id"] - class InitDataType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - CENC: LicenseRequest.ContentIdentification.InitData.InitDataType - INIT_DATA_FIELD_NUMBER: _ClassVar[int] - INIT_DATA_TYPE_FIELD_NUMBER: _ClassVar[int] - LICENSE_TYPE_FIELD_NUMBER: _ClassVar[int] - REQUEST_ID_FIELD_NUMBER: _ClassVar[int] - WEBM: LicenseRequest.ContentIdentification.InitData.InitDataType - init_data: bytes - init_data_type: LicenseRequest.ContentIdentification.InitData.InitDataType - license_type: LicenseType - request_id: bytes - def __init__(self, init_data_type: _Optional[_Union[LicenseRequest.ContentIdentification.InitData.InitDataType, str]] = ..., init_data: _Optional[bytes] = ..., license_type: _Optional[_Union[LicenseType, str]] = ..., request_id: _Optional[bytes] = ...) -> None: ... - class WebmKeyId(_message.Message): - __slots__ = ["header", "license_type", "request_id"] - HEADER_FIELD_NUMBER: _ClassVar[int] - LICENSE_TYPE_FIELD_NUMBER: _ClassVar[int] - REQUEST_ID_FIELD_NUMBER: _ClassVar[int] - header: bytes - license_type: LicenseType - request_id: bytes - def __init__(self, header: _Optional[bytes] = ..., license_type: _Optional[_Union[LicenseType, str]] = ..., request_id: _Optional[bytes] = ...) -> None: ... - class WidevinePsshData(_message.Message): - __slots__ = ["license_type", "pssh_data", "request_id"] - LICENSE_TYPE_FIELD_NUMBER: _ClassVar[int] - PSSH_DATA_FIELD_NUMBER: _ClassVar[int] - REQUEST_ID_FIELD_NUMBER: _ClassVar[int] - license_type: LicenseType - pssh_data: _containers.RepeatedScalarFieldContainer[bytes] - request_id: bytes - def __init__(self, pssh_data: _Optional[_Iterable[bytes]] = ..., license_type: _Optional[_Union[LicenseType, str]] = ..., request_id: _Optional[bytes] = ...) -> None: ... - EXISTING_LICENSE_FIELD_NUMBER: _ClassVar[int] - INIT_DATA_FIELD_NUMBER: _ClassVar[int] - WEBM_KEY_ID_FIELD_NUMBER: _ClassVar[int] - WIDEVINE_PSSH_DATA_FIELD_NUMBER: _ClassVar[int] - existing_license: LicenseRequest.ContentIdentification.ExistingLicense - init_data: LicenseRequest.ContentIdentification.InitData - webm_key_id: LicenseRequest.ContentIdentification.WebmKeyId - widevine_pssh_data: LicenseRequest.ContentIdentification.WidevinePsshData - def __init__(self, widevine_pssh_data: _Optional[_Union[LicenseRequest.ContentIdentification.WidevinePsshData, _Mapping]] = ..., webm_key_id: _Optional[_Union[LicenseRequest.ContentIdentification.WebmKeyId, _Mapping]] = ..., existing_license: _Optional[_Union[LicenseRequest.ContentIdentification.ExistingLicense, _Mapping]] = ..., init_data: _Optional[_Union[LicenseRequest.ContentIdentification.InitData, _Mapping]] = ...) -> None: ... - CLIENT_ID_FIELD_NUMBER: _ClassVar[int] - CONTENT_ID_FIELD_NUMBER: _ClassVar[int] - ENCRYPTED_CLIENT_ID_FIELD_NUMBER: _ClassVar[int] - KEY_CONTROL_NONCE_DEPRECATED_FIELD_NUMBER: _ClassVar[int] - KEY_CONTROL_NONCE_FIELD_NUMBER: _ClassVar[int] - NEW: LicenseRequest.RequestType - PROTOCOL_VERSION_FIELD_NUMBER: _ClassVar[int] - RELEASE: LicenseRequest.RequestType - RENEWAL: LicenseRequest.RequestType - REQUEST_TIME_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - client_id: ClientIdentification - content_id: LicenseRequest.ContentIdentification - encrypted_client_id: EncryptedClientIdentification - key_control_nonce: int - key_control_nonce_deprecated: bytes - protocol_version: ProtocolVersion - request_time: int - type: LicenseRequest.RequestType - def __init__(self, client_id: _Optional[_Union[ClientIdentification, _Mapping]] = ..., content_id: _Optional[_Union[LicenseRequest.ContentIdentification, _Mapping]] = ..., type: _Optional[_Union[LicenseRequest.RequestType, str]] = ..., request_time: _Optional[int] = ..., key_control_nonce_deprecated: _Optional[bytes] = ..., protocol_version: _Optional[_Union[ProtocolVersion, str]] = ..., key_control_nonce: _Optional[int] = ..., encrypted_client_id: _Optional[_Union[EncryptedClientIdentification, _Mapping]] = ...) -> None: ... - -class MetricData(_message.Message): - __slots__ = ["metric_data", "stage_name"] - class MetricType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class TypeValue(_message.Message): - __slots__ = ["type", "value"] - TYPE_FIELD_NUMBER: _ClassVar[int] - VALUE_FIELD_NUMBER: _ClassVar[int] - type: MetricData.MetricType - value: int - def __init__(self, type: _Optional[_Union[MetricData.MetricType, str]] = ..., value: _Optional[int] = ...) -> None: ... - LATENCY: MetricData.MetricType - METRIC_DATA_FIELD_NUMBER: _ClassVar[int] - STAGE_NAME_FIELD_NUMBER: _ClassVar[int] - TIMESTAMP: MetricData.MetricType - metric_data: _containers.RepeatedCompositeFieldContainer[MetricData.TypeValue] - stage_name: str - def __init__(self, stage_name: _Optional[str] = ..., metric_data: _Optional[_Iterable[_Union[MetricData.TypeValue, _Mapping]]] = ...) -> None: ... - -class SignedDrmCertificate(_message.Message): - __slots__ = ["drm_certificate", "hash_algorithm", "signature", "signer"] - DRM_CERTIFICATE_FIELD_NUMBER: _ClassVar[int] - HASH_ALGORITHM_FIELD_NUMBER: _ClassVar[int] - SIGNATURE_FIELD_NUMBER: _ClassVar[int] - SIGNER_FIELD_NUMBER: _ClassVar[int] - drm_certificate: bytes - hash_algorithm: HashAlgorithmProto - signature: bytes - signer: SignedDrmCertificate - def __init__(self, drm_certificate: _Optional[bytes] = ..., signature: _Optional[bytes] = ..., signer: _Optional[_Union[SignedDrmCertificate, _Mapping]] = ..., hash_algorithm: _Optional[_Union[HashAlgorithmProto, str]] = ...) -> None: ... - -class SignedMessage(_message.Message): - __slots__ = ["metric_data", "msg", "oemcrypto_core_message", "remote_attestation", "service_version_info", "session_key", "session_key_type", "signature", "type"] - class MessageType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class SessionKeyType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - CAS_LICENSE: SignedMessage.MessageType - CAS_LICENSE_REQUEST: SignedMessage.MessageType - EPHERMERAL_ECC_PUBLIC_KEY: SignedMessage.SessionKeyType - ERROR_RESPONSE: SignedMessage.MessageType - EXTERNAL_LICENSE: SignedMessage.MessageType - EXTERNAL_LICENSE_REQUEST: SignedMessage.MessageType - LICENSE: SignedMessage.MessageType - LICENSE_REQUEST: SignedMessage.MessageType - METRIC_DATA_FIELD_NUMBER: _ClassVar[int] - MSG_FIELD_NUMBER: _ClassVar[int] - OEMCRYPTO_CORE_MESSAGE_FIELD_NUMBER: _ClassVar[int] - REMOTE_ATTESTATION_FIELD_NUMBER: _ClassVar[int] - SERVICE_CERTIFICATE: SignedMessage.MessageType - SERVICE_CERTIFICATE_REQUEST: SignedMessage.MessageType - SERVICE_VERSION_INFO_FIELD_NUMBER: _ClassVar[int] - SESSION_KEY_FIELD_NUMBER: _ClassVar[int] - SESSION_KEY_TYPE_FIELD_NUMBER: _ClassVar[int] - SIGNATURE_FIELD_NUMBER: _ClassVar[int] - SUB_LICENSE: SignedMessage.MessageType - TYPE_FIELD_NUMBER: _ClassVar[int] - UNDEFINED: SignedMessage.SessionKeyType - WRAPPED_AES_KEY: SignedMessage.SessionKeyType - metric_data: _containers.RepeatedCompositeFieldContainer[MetricData] - msg: bytes - oemcrypto_core_message: bytes - remote_attestation: bytes - service_version_info: VersionInfo - session_key: bytes - session_key_type: SignedMessage.SessionKeyType - signature: bytes - type: SignedMessage.MessageType - def __init__(self, type: _Optional[_Union[SignedMessage.MessageType, str]] = ..., msg: _Optional[bytes] = ..., signature: _Optional[bytes] = ..., session_key: _Optional[bytes] = ..., remote_attestation: _Optional[bytes] = ..., metric_data: _Optional[_Iterable[_Union[MetricData, _Mapping]]] = ..., service_version_info: _Optional[_Union[VersionInfo, _Mapping]] = ..., session_key_type: _Optional[_Union[SignedMessage.SessionKeyType, str]] = ..., oemcrypto_core_message: _Optional[bytes] = ...) -> None: ... - -class VersionInfo(_message.Message): - __slots__ = ["license_sdk_version", "license_service_version"] - LICENSE_SDK_VERSION_FIELD_NUMBER: _ClassVar[int] - LICENSE_SERVICE_VERSION_FIELD_NUMBER: _ClassVar[int] - license_sdk_version: str - license_service_version: str - def __init__(self, license_sdk_version: _Optional[str] = ..., license_service_version: _Optional[str] = ...) -> None: ... - -class WidevinePsshData(_message.Message): - __slots__ = ["algorithm", "content_id", "crypto_period_index", "crypto_period_seconds", "entitled_keys", "group_ids", "grouped_license", "key_ids", "key_sequence", "policy", "protection_scheme", "provider", "track_type", "type", "video_feature"] - class Algorithm(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class Type(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - class EntitledKey(_message.Message): - __slots__ = ["entitlement_key_id", "entitlement_key_size_bytes", "iv", "key", "key_id"] - ENTITLEMENT_KEY_ID_FIELD_NUMBER: _ClassVar[int] - ENTITLEMENT_KEY_SIZE_BYTES_FIELD_NUMBER: _ClassVar[int] - IV_FIELD_NUMBER: _ClassVar[int] - KEY_FIELD_NUMBER: _ClassVar[int] - KEY_ID_FIELD_NUMBER: _ClassVar[int] - entitlement_key_id: bytes - entitlement_key_size_bytes: int - iv: bytes - key: bytes - key_id: bytes - def __init__(self, entitlement_key_id: _Optional[bytes] = ..., key_id: _Optional[bytes] = ..., key: _Optional[bytes] = ..., iv: _Optional[bytes] = ..., entitlement_key_size_bytes: _Optional[int] = ...) -> None: ... - AESCTR: WidevinePsshData.Algorithm - ALGORITHM_FIELD_NUMBER: _ClassVar[int] - CONTENT_ID_FIELD_NUMBER: _ClassVar[int] - CRYPTO_PERIOD_INDEX_FIELD_NUMBER: _ClassVar[int] - CRYPTO_PERIOD_SECONDS_FIELD_NUMBER: _ClassVar[int] - ENTITLED_KEY: WidevinePsshData.Type - ENTITLED_KEYS_FIELD_NUMBER: _ClassVar[int] - ENTITLEMENT: WidevinePsshData.Type - GROUPED_LICENSE_FIELD_NUMBER: _ClassVar[int] - GROUP_IDS_FIELD_NUMBER: _ClassVar[int] - KEY_IDS_FIELD_NUMBER: _ClassVar[int] - KEY_SEQUENCE_FIELD_NUMBER: _ClassVar[int] - POLICY_FIELD_NUMBER: _ClassVar[int] - PROTECTION_SCHEME_FIELD_NUMBER: _ClassVar[int] - PROVIDER_FIELD_NUMBER: _ClassVar[int] - SINGLE: WidevinePsshData.Type - TRACK_TYPE_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - UNENCRYPTED: WidevinePsshData.Algorithm - VIDEO_FEATURE_FIELD_NUMBER: _ClassVar[int] - algorithm: WidevinePsshData.Algorithm - content_id: bytes - crypto_period_index: int - crypto_period_seconds: int - entitled_keys: _containers.RepeatedCompositeFieldContainer[WidevinePsshData.EntitledKey] - group_ids: _containers.RepeatedScalarFieldContainer[bytes] - grouped_license: bytes - key_ids: _containers.RepeatedScalarFieldContainer[bytes] - key_sequence: int - policy: str - protection_scheme: int - provider: str - track_type: str - type: WidevinePsshData.Type - video_feature: str - def __init__(self, key_ids: _Optional[_Iterable[bytes]] = ..., content_id: _Optional[bytes] = ..., crypto_period_index: _Optional[int] = ..., protection_scheme: _Optional[int] = ..., crypto_period_seconds: _Optional[int] = ..., type: _Optional[_Union[WidevinePsshData.Type, str]] = ..., key_sequence: _Optional[int] = ..., group_ids: _Optional[_Iterable[bytes]] = ..., entitled_keys: _Optional[_Iterable[_Union[WidevinePsshData.EntitledKey, _Mapping]]] = ..., video_feature: _Optional[str] = ..., algorithm: _Optional[_Union[WidevinePsshData.Algorithm, str]] = ..., provider: _Optional[str] = ..., track_type: _Optional[str] = ..., policy: _Optional[str] = ..., grouped_license: _Optional[bytes] = ...) -> None: ... - -class LicenseType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - -class PlatformVerificationStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - -class ProtocolVersion(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - -class HashAlgorithmProto(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] diff --git a/scripts/pywidevine/pywidevine/main.py b/scripts/pywidevine/pywidevine/main.py deleted file mode 100644 index 301af51..0000000 --- a/scripts/pywidevine/pywidevine/main.py +++ /dev/null @@ -1,398 +0,0 @@ -import logging -from datetime import datetime -from pathlib import Path -from typing import Optional -from zlib import crc32 - -import click -import requests -import yaml -from construct import ConstructError -from google.protobuf.json_format import MessageToDict -from unidecode import UnidecodeError, unidecode - -from pywidevine import __version__ -from pywidevine.cdm import Cdm -from pywidevine.device import Device, DeviceTypes -from pywidevine.license_protocol_pb2 import FileHashes, LicenseType -from pywidevine.pssh import PSSH - - -@click.group(invoke_without_command=True) -@click.option("-v", "--version", is_flag=True, default=False, help="Print version information.") -@click.option("-d", "--debug", is_flag=True, default=False, help="Enable DEBUG level logs.") -def main(version: bool, debug: bool) -> None: - """pywidevine—Python Widevine CDM implementation.""" - logging.basicConfig(level=logging.DEBUG if debug else logging.INFO) - log = logging.getLogger() - - current_year = datetime.now().year - copyright_years = f"2022-{current_year}" - - log.info("pywidevine version %s Copyright (c) %s rlaphoenix", __version__, copyright_years) - log.info("https://github.com/devine-dl/pywidevine") - if version: - return - - -@main.command(name="license") -@click.argument("device_path", type=Path) -@click.argument("pssh", type=PSSH) -@click.argument("server", type=str) -@click.option("-t", "--type", "license_type", type=click.Choice(LicenseType.keys(), case_sensitive=False), - default="STREAMING", - help="License Type to Request.") -@click.option("-p", "--privacy", is_flag=True, default=False, - help="Use Privacy Mode, off by default.") -def license_(device_path: Path, pssh: PSSH, server: str, license_type: str, privacy: bool) -> None: - """ - Make a License Request for PSSH to SERVER using DEVICE. - It will return a list of all keys within the returned license. - - This expects the Licence Server to be a simple opaque interface where the Challenge - is sent as is (as bytes), and the License response is returned as is (as bytes). - This is a common behavior for some License Servers and is our only option for a generic - licensing function. - - You may modify this function to change how it sends the Challenge and how it parses - the License response. However, for non-generic license calls, I recommend creating a - new script that imports and uses the pywidevine module instead. This generic function - is only useful as a quick generic license call. - - This is also a great way of showing you how to use pywidevine in your own projects. - """ - log = logging.getLogger("license") - - # load device - device = Device.load(device_path) - log.info("[+] Loaded Device (%s L%s)", device.system_id, device.security_level) - log.debug(device) - - # load cdm - cdm = Cdm.from_device(device) - log.info("[+] Loaded CDM") - log.debug(cdm) - - # open cdm session - session_id = cdm.open() - log.info("[+] Opened CDM Session: %s", session_id.hex()) - - if privacy: - # get service cert for license server via cert challenge - service_cert_res = requests.post( - url=server, - data=cdm.service_certificate_challenge - ) - if service_cert_res.status_code != 200: - log.error( - "[-] Failed to get Service Privacy Certificate: [%s] %s", - service_cert_res.status_code, - service_cert_res.text - ) - return - service_cert = service_cert_res.content - provider_id = cdm.set_service_certificate(session_id, service_cert) - log.info("[+] Set Service Privacy Certificate: %s", provider_id) - log.debug(service_cert) - - # get license challenge - challenge = cdm.get_license_challenge(session_id, pssh, license_type, privacy_mode=True) - log.info("[+] Created License Request Message (Challenge)") - log.debug(challenge) - - # send license challenge - license_res = requests.post( - url=server, - data=challenge - ) - if license_res.status_code != 200: - log.error("[-] Failed to send challenge: [%s] %s", license_res.status_code, license_res.text) - return - licence = license_res.content - log.info("[+] Got License Message") - log.debug(licence) - - # parse license challenge - cdm.parse_license(session_id, licence) - log.info("[+] License Parsed Successfully") - - # print keys - for key in cdm.get_keys(session_id): - log.info("[%s] %s:%s", key.type, key.kid.hex, key.key.hex()) - - # close session, disposes of session data - cdm.close(session_id) - - -@main.command() -@click.argument("device", type=Path) -@click.option("-p", "--privacy", is_flag=True, default=False, - help="Use Privacy Mode, off by default.") -@click.pass_context -def test(ctx: click.Context, device: Path, privacy: bool) -> None: - """ - Test the CDM code by getting Content Keys for Bitmovin's Art of Motion example. - https://bitmovin.com/demos/drm - https://bitmovin-a.akamaihd.net/content/art-of-motion_drm/mpds/11331.mpd - - The device argument is a Path to a Widevine Device (.wvd) file which contains - the device private key among other required information. - """ - # The PSSH is the same for all tracks both video and audio. - # However, this might not be the case for all services/manifests. - pssh = PSSH("AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa" - "7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA==") - - # This License Server requires no authorization at all, no cookies, no credentials - # nothing. This is often not the case for real services. - license_server = "https://cwip-shaka-proxy.appspot.com/no_auth" - - # Specify OFFLINE if it's a PSSH for a download/offline mode title, e.g., the - # Download feature on Netflix Apps. Otherwise, use STREAMING or AUTOMATIC. - license_type = "STREAMING" - - # this runs the `cdm license` CLI-command code with the data we set above - # it will print information as it goes to the terminal - ctx.invoke( - license_, - device_path=device, - pssh=pssh, - server=license_server, - license_type=license_type, - privacy=privacy - ) - - -@main.command() -@click.option("-t", "--type", "type_", type=click.Choice([x.name for x in DeviceTypes], case_sensitive=False), - required=True, help="Device Type") -@click.option("-l", "--level", type=click.IntRange(1, 3), required=True, help="Device Security Level") -@click.option("-k", "--key", type=Path, required=True, help="Device RSA Private Key in PEM or DER format") -@click.option("-c", "--client_id", type=Path, required=True, help="Widevine ClientIdentification Blob file") -@click.option("-v", "--vmp", type=Path, default=None, help="Widevine FileHashes Blob file") -@click.option("-o", "--output", type=Path, default=None, help="Output Path or Directory") -@click.pass_context -def create_device( - ctx: click.Context, - type_: str, - level: int, - key: Path, - client_id: Path, - vmp: Optional[Path] = None, - output: Optional[Path] = None -) -> None: - """ - Create a Widevine Device (.wvd) file from an RSA Private Key (PEM or DER) and Client ID Blob. - Optionally also a VMP (Verified Media Path) Blob, which will be stored in the Client ID. - """ - if not key.is_file(): - raise click.UsageError("key: Not a path to a file, or it doesn't exist.", ctx) - if not client_id.is_file(): - raise click.UsageError("client_id: Not a path to a file, or it doesn't exist.", ctx) - if vmp and not vmp.is_file(): - raise click.UsageError("vmp: Not a path to a file, or it doesn't exist.", ctx) - - log = logging.getLogger("create-device") - - device = Device( - type_=DeviceTypes[type_.upper()], - security_level=level, - flags=None, - private_key=key.read_bytes(), - client_id=client_id.read_bytes() - ) - - if vmp: - new_vmp_data = vmp.read_bytes() - if device.client_id.vmp_data and device.client_id.vmp_data != new_vmp_data: - log.warning("Client ID already has Verified Media Path data") - device.client_id.vmp_data = new_vmp_data - - client_info = {} - for entry in device.client_id.client_info: - client_info[entry.name] = entry.value - - wvd_bin = device.dumps() - - name = f"{client_info['company_name']} {client_info['model_name']}" - if client_info.get("widevine_cdm_version"): - name += f" {client_info['widevine_cdm_version']}" - name += f" {crc32(wvd_bin).to_bytes(4, 'big').hex()}" - - try: - name = unidecode(name.strip().lower().replace(" ", "_")) - except UnidecodeError as e: - raise click.ClickException(f"Failed to sanitize name, {e}") - - if output and output.suffix: - if output.suffix.lower() != ".wvd": - log.warning(f"Saving WVD with the file extension '{output.suffix}' but '.wvd' is recommended.") - out_path = output - else: - out_dir = output or Path.cwd() - out_path = out_dir / f"{name}_{device.system_id}_l{device.security_level}.wvd" - - if out_path.exists(): - log.error(f"A file already exists at the path '{out_path}', cannot overwrite.") - return - - out_path.parent.mkdir(parents=True, exist_ok=True) - out_path.write_bytes(wvd_bin) - - log.info("Created Widevine Device (.wvd) file, %s", out_path.name) - log.info(" + Type: %s", device.type.name) - log.info(" + System ID: %s", device.system_id) - log.info(" + Security Level: %s", device.security_level) - log.info(" + Flags: %s", device.flags) - log.info(" + Private Key: %s (%s bit)", bool(device.private_key), device.private_key.size_in_bits()) - log.info(" + Client ID: %s (%s bytes)", bool(device.client_id), len(device.client_id.SerializeToString())) - if device.client_id.vmp_data: - file_hashes_ = FileHashes() - file_hashes_.ParseFromString(device.client_id.vmp_data) - log.info(" + VMP: True (%s signatures)", len(file_hashes_.signatures)) - else: - log.info(" + VMP: False") - log.info(" + Saved to: %s", out_path.absolute()) - - -@main.command() -@click.argument("wvd_path", type=Path) -@click.option("-o", "--out_dir", type=Path, default=None, help="Output Directory") -@click.pass_context -def export_device(ctx: click.Context, wvd_path: Path, out_dir: Optional[Path] = None) -> None: - """ - Export a Widevine Device (.wvd) file to an RSA Private Key (PEM and DER) and Client ID Blob. - Optionally also a VMP (Verified Media Path) Blob, which will be stored in the Client ID. - - If an output directory is not specified, it will be stored in the current working directory. - """ - if not wvd_path.is_file(): - raise click.UsageError("wvd_path: Not a path to a file, or it doesn't exist.", ctx) - - log = logging.getLogger("export-device") - log.info("Exporting Widevine Device (.wvd) file, %s", wvd_path.stem) - - if not out_dir: - out_dir = Path.cwd() - - out_path = out_dir / wvd_path.stem - if out_path.exists(): - if any(out_path.iterdir()): - log.error("Output directory is not empty, cannot overwrite.") - return - else: - log.warning("Output directory already exists, but is empty.") - else: - out_path.mkdir(parents=True) - - device = Device.load(wvd_path) - - log.info(f"L{device.security_level} {device.system_id} {device.type.name}") - log.info(f"Saving to: {out_path}") - - device_meta = { - "wvd": { - "device_type": device.type.name, - "security_level": device.security_level, - **device.flags - }, - "client_info": {}, - "capabilities": MessageToDict(device.client_id, preserving_proto_field_name=True)["client_capabilities"] - } - for client_info in device.client_id.client_info: - device_meta["client_info"][client_info.name] = client_info.value - - device_meta_path = out_path / "metadata.yml" - device_meta_path.write_text(yaml.dump(device_meta), encoding="utf8") - log.info("Exported Device Metadata as metadata.yml") - - if device.private_key: - private_key_path = out_path / "private_key.pem" - private_key_path.write_text( - data=device.private_key.export_key().decode(), - encoding="utf8" - ) - private_key_path.with_suffix(".der").write_bytes( - device.private_key.export_key(format="DER") - ) - log.info("Exported Private Key as private_key.der and private_key.pem") - else: - log.warning("No Private Key available") - - if device.client_id: - client_id_path = out_path / "client_id.bin" - client_id_path.write_bytes(device.client_id.SerializeToString()) - log.info("Exported Client ID as client_id.bin") - else: - log.warning("No Client ID available") - - if device.client_id.vmp_data: - vmp_path = out_path / "vmp.bin" - vmp_path.write_bytes(device.client_id.vmp_data) - log.info("Exported VMP (File Hashes) as vmp.bin") - else: - log.info("No VMP (File Hashes) available") - - -@main.command() -@click.argument("path", type=Path) -@click.pass_context -def migrate(ctx: click.Context, path: Path) -> None: - """ - Upgrade from earlier versions of the Widevine Device (.wvd) format. - - The path argument can be a direct path to a Widevine Device (.wvd) file, or a path - to a folder of Widevine Devices files. - - The migrated devices are saved to its original location, overwriting the old version. - """ - if not path.exists(): - raise click.UsageError(f"path: The path '{path}' does not exist.", ctx) - - log = logging.getLogger("migrate") - - if path.is_dir(): - devices = list(path.glob("*.wvd")) - else: - devices = [path] - - migrated = 0 - for device in devices: - log.info("Migrating %s...", device.name) - - try: - new_device = Device.migrate(device.read_bytes()) - except (ConstructError, ValueError) as e: - log.error(" - %s", e) - continue - - log.debug(new_device) - new_device.dump(device) - - log.info(" + Success") - migrated += 1 - - log.info("Migrated %s/%s devices!", migrated, len(devices)) - - -@main.command("serve", short_help="Serve your local CDM and Widevine Devices Remotely.") -@click.argument("config_path", type=Path) -@click.option("-h", "--host", type=str, default="127.0.0.1", help="Host to serve from.") -@click.option("-p", "--port", type=int, default=8786, help="Port to serve from.") -def serve_(config_path: Path, host: str, port: int) -> None: - """ - Serve your local CDM and Widevine Devices Remotely. - - \b - [CONFIG] is a path to a serve config file. - See `serve.example.yml` for an example config file. - - \b - Host as 127.0.0.1 may block remote access even if port-forwarded. - Instead, use 0.0.0.0 and ensure the TCP port you choose is forwarded. - """ - from pywidevine import serve # isort:skip - import yaml # isort:skip - - config = yaml.safe_load(config_path.read_text(encoding="utf8")) - serve.run(config, host, port) diff --git a/scripts/pywidevine/pywidevine/pssh.py b/scripts/pywidevine/pywidevine/pssh.py deleted file mode 100644 index b81111a..0000000 --- a/scripts/pywidevine/pywidevine/pssh.py +++ /dev/null @@ -1,442 +0,0 @@ -from __future__ import annotations - -import base64 -import binascii -import string -from io import BytesIO -from typing import Optional, Union -from uuid import UUID -from xml.etree.ElementTree import XML - -import construct -from construct import Container -from google.protobuf.message import DecodeError -from pymp4.parser import Box - -from pywidevine.license_protocol_pb2 import WidevinePsshData - - -class PSSH: - """ - MP4 PSSH Box-related utilities. - Allows you to load, create, and modify various kinds of DRM system headers. - """ - - class SystemId: - Widevine = UUID(hex="edef8ba979d64acea3c827dcd51d21ed") - PlayReady = UUID(hex="9a04f07998404286ab92e65be0885f95") - - def __init__(self, data: Union[Container, str, bytes], strict: bool = False): - """ - Load a PSSH box, WidevineCencHeader, or PlayReadyHeader. - - When loading a WidevineCencHeader or PlayReadyHeader, a new v0 PSSH box will be - created and the header will be parsed and stored in the init_data field. However, - PlayReadyHeaders (and PlayReadyObjects) are not yet currently parsed and are - stored as bytes. - - [Strict mode (strict=True)] - - Supports the following forms of input data in either Base64 or Bytes form: - - Full PSSH mp4 boxes (as defined by pymp4 Box). - - Full Widevine Cenc Headers (as defined by WidevinePsshData proto). - - Full PlayReady Objects and Headers (as defined by Microsoft Docs). - - [Lenient mode (strict=False, default)] - - If the data is not supported in Strict mode, and is assumed not to be corrupt or - parsed incorrectly, the License Server likely accepts a custom init_data value - during a License Request call. This is uncommon behavior but not out of realm of - possibilities. For example, Netflix does this with it's MSL WidevineExchange - scheme. - - Lenient mode will craft a new v0 PSSH box with the init_data field set to - the provided data as-is. The data will first be base64 decoded. This behavior - may not work in your scenario and if that's the case please manually craft - your own PSSH box with the init_data field to be used in License Requests. - - Raises: - ValueError: If the data is empty. - TypeError: If the data is an unexpected type. - binascii.Error: If the data could not be decoded as Base64 if provided as a - string. - DecodeError: If the data could not be parsed as a PSSH mp4 box nor a Widevine - Cenc Header and strict mode is enabled. - """ - if not data: - raise ValueError("Data must not be empty.") - - if isinstance(data, Container): - box = data - else: - if isinstance(data, str): - try: - data = base64.b64decode(data) - except (binascii.Error, binascii.Incomplete) as e: - raise binascii.Error(f"Could not decode data as Base64, {e}") - - if not isinstance(data, bytes): - raise TypeError(f"Expected data to be a {Container}, bytes, or base64, not {data!r}") - - try: - box = Box.parse(data) - except (IOError, construct.ConstructError): # not a box - try: - widevine_pssh_data = WidevinePsshData() - widevine_pssh_data.ParseFromString(data) - data_serialized = widevine_pssh_data.SerializeToString() - if data_serialized != data: # not actually a WidevinePsshData - raise DecodeError() - box = Box.parse(Box.build(dict( - type=b"pssh", - version=0, - flags=0, - system_ID=PSSH.SystemId.Widevine, - init_data=data_serialized - ))) - except DecodeError: # not a widevine cenc header - if "".encode("utf-16-le") in data: - # TODO: Actually parse `data` as a PlayReadyHeader object and store that instead - box = Box.parse(Box.build(dict( - type=b"pssh", - version=0, - flags=0, - system_ID=PSSH.SystemId.PlayReady, - init_data=data - ))) - elif strict: - raise DecodeError(f"Could not parse data as a {Container} nor a {WidevinePsshData}.") - else: - # Data is not a WidevineCencHeader nor a PlayReadyHeader. - # The license server likely has something custom to parse it. - # See doc-string about Lenient mode for more information. - box = Box.parse(Box.build(dict( - type=b"pssh", - version=0, - flags=0, - system_ID=PSSH.SystemId.Widevine, - init_data=data - ))) - - self.version = box.version - self.flags = box.flags - self.system_id = box.system_ID - self.__key_ids = box.key_IDs - self.init_data = box.init_data - - def __repr__(self) -> str: - return f"PSSH<{self.system_id}>(v{self.version}; {self.flags}, {self.key_ids}, {self.init_data})" - - def __str__(self) -> str: - return self.dumps() - - @classmethod - def new( - cls, - system_id: UUID, - key_ids: Optional[list[Union[UUID, str, bytes]]] = None, - init_data: Optional[Union[WidevinePsshData, str, bytes]] = None, - version: int = 0, - flags: int = 0 - ) -> PSSH: - """Craft a new version 0 or 1 PSSH Box.""" - if not system_id: - raise ValueError("A System ID must be specified.") - if not isinstance(system_id, UUID): - raise TypeError(f"Expected system_id to be a UUID, not {system_id!r}") - - if key_ids is not None and not isinstance(key_ids, list): - raise TypeError(f"Expected key_ids to be a list not {key_ids!r}") - - if init_data is not None and not isinstance(init_data, (WidevinePsshData, str, bytes)): - raise TypeError(f"Expected init_data to be a {WidevinePsshData}, base64, or bytes, not {init_data!r}") - - if not isinstance(version, int): - raise TypeError(f"Expected version to be an int not {version!r}") - if version not in (0, 1): - raise ValueError(f"Invalid version, must be either 0 or 1, not {version}.") - - if not isinstance(flags, int): - raise TypeError(f"Expected flags to be an int not {flags!r}") - if flags < 0: - raise ValueError("Invalid flags, cannot be less than 0.") - - if version == 0 and key_ids is not None and init_data is not None: - # v0 boxes use only init_data in the pssh field, but we can use the key_ids within the init_data - raise ValueError("Version 0 PSSH boxes must use only init_data, not init_data and key_ids.") - elif version == 1: - # TODO: I cannot tell if they need either init_data or key_ids exclusively, or both is fine - # So for now I will just make sure at least one is supplied - if init_data is None and key_ids is None: - raise ValueError("Version 1 PSSH boxes must use either init_data or key_ids but neither were provided") - - if init_data is not None: - if isinstance(init_data, WidevinePsshData): - init_data = init_data.SerializeToString() - elif isinstance(init_data, str): - if all(c in string.hexdigits for c in init_data): - init_data = bytes.fromhex(init_data) - else: - init_data = base64.b64decode(init_data) - elif not isinstance(init_data, bytes): - raise TypeError( - f"Expecting init_data to be {WidevinePsshData}, hex, base64, or bytes, not {init_data!r}" - ) - - pssh = cls(Box.parse(Box.build(dict( - type=b"pssh", - version=version, - flags=flags, - system_ID=system_id, - init_data=[init_data, b""][init_data is None] - # key_IDs should not be set yet - )))) - - if key_ids: - # We must reinforce the version because pymp4 forces v0 if key_IDs is not set. - # The set_key_ids() func will set it efficiently in both init_data and the box where needed. - # The version must be reinforced ONLY if we have key_id data or there's a possibility of making - # a v1 PSSH box, that did not have key_IDs set in the PSSH box. - pssh.version = version - pssh.set_key_ids(key_ids) - - return pssh - - @property - def key_ids(self) -> list[UUID]: - """ - Get all Key IDs from within the Box or Init Data, wherever possible. - - Supports: - - Version 1 PSSH Boxes - - WidevineCencHeaders - - PlayReadyHeaders (4.0.0.0->4.3.0.0) - """ - if self.version == 1 and self.__key_ids: - return self.__key_ids - - if self.system_id == PSSH.SystemId.Widevine: - # TODO: What if its not a Widevine Cenc Header but the System ID is set as Widevine? - cenc_header = WidevinePsshData() - cenc_header.ParseFromString(self.init_data) - return [ - # the key_ids value may or may not be hex underlying - ( - UUID(bytes=key_id) if len(key_id) == 16 else # normal - UUID(hex=key_id.decode()) if len(key_id) == 32 else # stored as hex - UUID(int=int.from_bytes(key_id, "big")) # assuming as number - ) - for key_id in cenc_header.key_ids - ] - - if self.system_id == PSSH.SystemId.PlayReady: - # Assuming init data is a PRO (PlayReadyObject) - # https://learn.microsoft.com/en-us/playready/specifications/playready-header-specification - pro_data = BytesIO(self.init_data) - pro_length = int.from_bytes(pro_data.read(4), "little") - if pro_length != len(self.init_data): - raise ValueError("The PlayReadyObject seems to be corrupt (too big or small, or missing data).") - pro_record_count = int.from_bytes(pro_data.read(2), "little") - - for _ in range(pro_record_count): - prr_type = int.from_bytes(pro_data.read(2), "little") - prr_length = int.from_bytes(pro_data.read(2), "little") - prr_value = pro_data.read(prr_length) - if prr_type != 0x01: - # No PlayReady Header, skip and hope for something else - # TODO: Add support for Embedded License Stores (0x03) - continue - - wrm_ns = {"wrm": "http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader"} - prr_header = XML(prr_value.decode("utf-16-le")) - prr_header_version = prr_header.get("version") - if prr_header_version == "4.0.0.0": - key_ids = [ - x.text - for x in prr_header.findall("./wrm:DATA/wrm:KID", wrm_ns) - if x.text - ] - elif prr_header_version == "4.1.0.0": - key_ids = [ - x.attrib["VALUE"] - for x in prr_header.findall("./wrm:DATA/wrm:PROTECTINFO/wrm:KID", wrm_ns) - ] - elif prr_header_version in ("4.2.0.0", "4.3.0.0"): - # TODO: Retain the Encryption Scheme information in v4.3.0.0 - # This is because some Key IDs can be AES-CTR while some are AES-CBC. - # Conversion to WidevineCencHeader could use this information. - key_ids = [ - x.attrib["VALUE"] - for x in prr_header.findall("./wrm:DATA/wrm:PROTECTINFO/wrm:KIDS/wrm:KID", wrm_ns) - ] - else: - raise ValueError(f"Unsupported PlayReadyHeader version {prr_header_version}") - - return [ - UUID(bytes=base64.b64decode(key_id)) - for key_id in key_ids - ] - - raise ValueError("Unsupported PlayReadyObject, no PlayReadyHeader within the object.") - - raise ValueError(f"This PSSH is not supported by key_ids() property, {self.dumps()}") - - def dump(self) -> bytes: - """Export the PSSH object as a full PSSH box in bytes form.""" - return Box.build(dict( - type=b"pssh", - version=self.version, - flags=self.flags, - system_ID=self.system_id, - key_IDs=self.key_ids if self.version == 1 and self.key_ids else None, - init_data=self.init_data - )) - - def dumps(self) -> str: - """Export the PSSH object as a full PSSH box in base64 form.""" - return base64.b64encode(self.dump()).decode() - - def to_widevine(self) -> None: - """ - Convert PlayReady PSSH data to Widevine PSSH data. - - There's only a limited amount of information within a PlayReady PSSH header that - can be used in a Widevine PSSH Header. The converted data may or may not result - in an accepted PSSH. It depends on what the License Server is expecting. - """ - if self.system_id == PSSH.SystemId.Widevine: - raise ValueError("This is already a Widevine PSSH") - - widevine_pssh_data = WidevinePsshData( - key_ids=[x.bytes for x in self.key_ids], - algorithm="AESCTR" - ) - - if self.version == 1: - # ensure both cenc header and box has same Key IDs - # v1 uses both this and within init data for basically no reason - self.__key_ids = self.key_ids - - self.init_data = widevine_pssh_data.SerializeToString() - self.system_id = PSSH.SystemId.Widevine - - def to_playready( - self, - la_url: Optional[str] = None, - lui_url: Optional[str] = None, - ds_id: Optional[bytes] = None, - decryptor_setup: Optional[str] = None, - custom_data: Optional[str] = None - ) -> None: - """ - Convert Widevine PSSH data to PlayReady v4.3.0.0 PSSH data. - - Note that it is impossible to create the CHECKSUM values for AES-CTR Key IDs - as you must encrypt the Key ID with the Content Encryption Key using AES-ECB. - This may cause software incompatibilities. - - Parameters: - la_url: Contains the URL for the license acquisition Web service. - Only absolute URLs are allowed. - lui_url: Contains the URL for the license acquisition Web service. - Only absolute URLs are allowed. - ds_id: Service ID for the domain service. - decryptor_setup: This tag may only contain the value "ONDEMAND". It - indicates to an application that it should not expect the full - license chain for the content to be available for acquisition, or - already present on the client machine, prior to setting up the - media graph. If this tag is not set then it indicates that an - application can enforce the license to be acquired, or already - present on the client machine, prior to setting up the media graph. - custom_data: The content author can add custom XML inside this - element. Microsoft code does not act on any data contained inside - this element. The Syntax of this params XML is not validated. - """ - if self.system_id == PSSH.SystemId.PlayReady: - raise ValueError("This is already a PlayReady PSSH") - - key_ids_xml = "" - for key_id in self.key_ids: - # Note that it's impossible to create the CHECKSUM value without the Key for the KID - key_ids_xml += f""" - - """ - - prr_value = f""" - - - - {key_ids_xml} - - {'%s' % la_url if la_url else ''} - {'%s' % lui_url if lui_url else ''} - {'%s' % base64.b64encode(ds_id).decode() if ds_id else ''} - {'%s' % decryptor_setup if decryptor_setup else ''} - {'%s' % custom_data if custom_data else ''} - - - """.encode("utf-16-le") - - prr_length = len(prr_value).to_bytes(2, "little") - prr_type = (1).to_bytes(2, "little") # Has PlayReadyHeader - pro_record_count = (1).to_bytes(2, "little") - pro = pro_record_count + prr_type + prr_length + prr_value - pro = (len(pro) + 4).to_bytes(4, "little") + pro - - self.init_data = pro - self.system_id = PSSH.SystemId.PlayReady - - def set_key_ids(self, key_ids: list[Union[UUID, str, bytes]]) -> None: - """Overwrite all Key IDs with the specified Key IDs.""" - if self.system_id != PSSH.SystemId.Widevine: - # TODO: Add support for setting the Key IDs in a PlayReady Header - raise ValueError(f"Only Widevine PSSH Boxes are supported, not {self.system_id}.") - - key_id_uuids = self.parse_key_ids(key_ids) - - if self.version == 1 or self.__key_ids: - # only use v1 box key_ids if version is 1, or it's already being used - # this is in case the service stupidly expects it for version 0 - self.__key_ids = key_id_uuids - - cenc_header = WidevinePsshData() - cenc_header.ParseFromString(self.init_data) - - cenc_header.key_ids[:] = [ - key_id.bytes - for key_id in key_id_uuids - ] - - self.init_data = cenc_header.SerializeToString() - - @staticmethod - def parse_key_ids(key_ids: list[Union[UUID, str, bytes]]) -> list[UUID]: - """ - Parse a list of Key IDs in hex, base64, or bytes to UUIDs. - - Raises TypeError if `key_ids` is not a list, or the list contains one - or more items that are not a UUID, str, or bytes object. - """ - if not isinstance(key_ids, list): - raise TypeError(f"Expected key_ids to be a list, not {key_ids!r}") - - if not all(isinstance(x, (UUID, str, bytes)) for x in key_ids): - raise TypeError("Some items of key_ids are not a UUID, str, or bytes. Unsure how to continue...") - - uuids = [ - UUID(bytes=key_id_b) - for key_id in key_ids - for key_id_b in [ - key_id.bytes if isinstance(key_id, UUID) else - ( - bytes.fromhex(key_id) if all(c in string.hexdigits for c in key_id) else - base64.b64decode(key_id) - ) if isinstance(key_id, str) else - key_id - ] - ] - - return uuids - - -__all__ = ("PSSH",) diff --git a/scripts/pywidevine/pywidevine/remotecdm.py b/scripts/pywidevine/pywidevine/remotecdm.py deleted file mode 100644 index 7e79ce0..0000000 --- a/scripts/pywidevine/pywidevine/remotecdm.py +++ /dev/null @@ -1,300 +0,0 @@ -from __future__ import annotations - -import base64 -import binascii -import re -from typing import Optional, Union - -import requests -from Crypto.Hash import SHA1 -from Crypto.PublicKey import RSA -from Crypto.Signature import pss -from google.protobuf.message import DecodeError - -from pywidevine.cdm import Cdm -from pywidevine.device import Device, DeviceTypes -from pywidevine.exceptions import (DeviceMismatch, InvalidInitData, InvalidLicenseMessage, InvalidLicenseType, - SignatureMismatch) -from pywidevine.key import Key -from pywidevine.license_protocol_pb2 import (ClientIdentification, License, LicenseType, SignedDrmCertificate, - SignedMessage) -from pywidevine.pssh import PSSH - - -class RemoteCdm(Cdm): - """Remote Accessible CDM using pywidevine's serve schema.""" - - def __init__( - self, - device_type: Union[DeviceTypes, str], - system_id: int, - security_level: int, - host: str, - secret: str, - device_name: str - ): - """Initialize a Widevine Content Decryption Module (CDM).""" - if not device_type: - raise ValueError("Device Type must be provided") - if isinstance(device_type, str): - device_type = DeviceTypes[device_type] - if not isinstance(device_type, DeviceTypes): - raise TypeError(f"Expected device_type to be a {DeviceTypes!r} not {device_type!r}") - - if not system_id: - raise ValueError("System ID must be provided") - if not isinstance(system_id, int): - raise TypeError(f"Expected system_id to be a {int} not {system_id!r}") - - if not security_level: - raise ValueError("Security Level must be provided") - if not isinstance(security_level, int): - raise TypeError(f"Expected security_level to be a {int} not {security_level!r}") - - if not host: - raise ValueError("API Host must be provided") - if not isinstance(host, str): - raise TypeError(f"Expected host to be a {str} not {host!r}") - - if not secret: - raise ValueError("API Secret must be provided") - if not isinstance(secret, str): - raise TypeError(f"Expected secret to be a {str} not {secret!r}") - - if not device_name: - raise ValueError("API Device name must be provided") - if not isinstance(device_name, str): - raise TypeError(f"Expected device_name to be a {str} not {device_name!r}") - - self.device_type = device_type - self.system_id = system_id - self.security_level = security_level - self.host = host - self.device_name = device_name - - # spoof client_id and rsa_key just so we can construct via super call - super().__init__(device_type, system_id, security_level, ClientIdentification(), RSA.generate(2048)) - - self.__session = requests.Session() - self.__session.headers.update({ - "X-Secret-Key": secret - }) - - r = requests.head(self.host) - if r.status_code != 200: - raise ValueError(f"Could not test Remote API version [{r.status_code}]") - server = r.headers.get("Server") - if not server or "pywidevine serve" not in server.lower(): - raise ValueError(f"This Remote CDM API does not seem to be a pywidevine serve API ({server}).") - server_version_re = re.search(r"pywidevine serve v([\d.]+)", server, re.IGNORECASE) - if not server_version_re: - raise ValueError("The pywidevine server API is not stating the version correctly, cannot continue.") - server_version = server_version_re.group(1) - if server_version < "1.4.3": - raise ValueError(f"This pywidevine serve API version ({server_version}) is not supported.") - - @classmethod - def from_device(cls, device: Device) -> RemoteCdm: - raise NotImplementedError("You cannot load a RemoteCdm from a local Device file.") - - def open(self) -> bytes: - r = self.__session.get( - url=f"{self.host}/{self.device_name}/open" - ).json() - if r['status'] != 200: - raise ValueError(f"Cannot Open CDM Session, {r['message']} [{r['status']}]") - r = r["data"] - - if int(r["device"]["system_id"]) != self.system_id: - raise DeviceMismatch("The System ID specified does not match the one specified in the API response.") - - if int(r["device"]["security_level"]) != self.security_level: - raise DeviceMismatch("The Security Level specified does not match the one specified in the API response.") - - return bytes.fromhex(r["session_id"]) - - def close(self, session_id: bytes) -> None: - r = self.__session.get( - url=f"{self.host}/{self.device_name}/close/{session_id.hex()}" - ).json() - if r["status"] != 200: - raise ValueError(f"Cannot Close CDM Session, {r['message']} [{r['status']}]") - - def set_service_certificate(self, session_id: bytes, certificate: Optional[Union[bytes, str]]) -> str: - if certificate is None: - certificate_b64 = None - elif isinstance(certificate, str): - certificate_b64 = certificate # assuming base64 - elif isinstance(certificate, bytes): - certificate_b64 = base64.b64encode(certificate).decode() - else: - raise DecodeError(f"Expecting Certificate to be base64 or bytes, not {certificate!r}") - - r = self.__session.post( - url=f"{self.host}/{self.device_name}/set_service_certificate", - json={ - "session_id": session_id.hex(), - "certificate": certificate_b64 - } - ).json() - if r["status"] != 200: - raise ValueError(f"Cannot Set CDMs Service Certificate, {r['message']} [{r['status']}]") - r = r["data"] - - return r["provider_id"] - - def get_service_certificate(self, session_id: bytes) -> Optional[SignedDrmCertificate]: - r = self.__session.post( - url=f"{self.host}/{self.device_name}/get_service_certificate", - json={ - "session_id": session_id.hex() - } - ).json() - if r["status"] != 200: - raise ValueError(f"Cannot Get CDMs Service Certificate, {r['message']} [{r['status']}]") - r = r["data"] - - service_certificate = r["service_certificate"] - if not service_certificate: - return None - - service_certificate = base64.b64decode(service_certificate) - signed_drm_certificate = SignedDrmCertificate() - - try: - signed_drm_certificate.ParseFromString(service_certificate) - if signed_drm_certificate.SerializeToString() != service_certificate: - raise DecodeError("partial parse") - except DecodeError as e: - # could be a direct unsigned DrmCertificate, but reject those anyway - raise DecodeError(f"Could not parse certificate as a SignedDrmCertificate, {e}") - - try: - pss. \ - new(RSA.import_key(self.root_cert.public_key)). \ - verify( - msg_hash=SHA1.new(signed_drm_certificate.drm_certificate), - signature=signed_drm_certificate.signature - ) - except (ValueError, TypeError): - raise SignatureMismatch("Signature Mismatch on SignedDrmCertificate, rejecting certificate") - - return signed_drm_certificate - - def get_license_challenge( - self, - session_id: bytes, - pssh: PSSH, - license_type: str = "STREAMING", - privacy_mode: bool = True - ) -> bytes: - if not pssh: - raise InvalidInitData("A pssh must be provided.") - if not isinstance(pssh, PSSH): - raise InvalidInitData(f"Expected pssh to be a {PSSH}, not {pssh!r}") - - if not isinstance(license_type, str): - raise InvalidLicenseType(f"Expected license_type to be a {str}, not {license_type!r}") - if license_type not in LicenseType.keys(): - raise InvalidLicenseType( - f"Invalid license_type value of '{license_type}'. " - f"Available values: {LicenseType.keys()}" - ) - - r = self.__session.post( - url=f"{self.host}/{self.device_name}/get_license_challenge/{license_type}", - json={ - "session_id": session_id.hex(), - "init_data": pssh.dumps(), - "privacy_mode": privacy_mode - } - ).json() - if r["status"] != 200: - raise ValueError(f"Cannot get Challenge, {r['message']} [{r['status']}]") - r = r["data"] - - try: - challenge = base64.b64decode(r["challenge_b64"]) - license_message = SignedMessage() - license_message.ParseFromString(challenge) - if license_message.SerializeToString() != challenge: - raise DecodeError("partial parse") - except DecodeError as e: - raise InvalidLicenseMessage(f"Failed to parse license request, {e}") - - return license_message.SerializeToString() - - def parse_license(self, session_id: bytes, license_message: Union[SignedMessage, bytes, str]) -> None: - if not license_message: - raise InvalidLicenseMessage("Cannot parse an empty license_message") - - if isinstance(license_message, str): - try: - license_message = base64.b64decode(license_message) - except (binascii.Error, binascii.Incomplete) as e: - raise InvalidLicenseMessage(f"Could not decode license_message as Base64, {e}") - - if isinstance(license_message, bytes): - signed_message = SignedMessage() - try: - signed_message.ParseFromString(license_message) - if signed_message.SerializeToString() != license_message: - raise DecodeError("partial parse") - except DecodeError as e: - raise InvalidLicenseMessage(f"Could not parse license_message as a SignedMessage, {e}") - license_message = signed_message - - if not isinstance(license_message, SignedMessage): - raise InvalidLicenseMessage(f"Expecting license_response to be a SignedMessage, got {license_message!r}") - - if license_message.type != SignedMessage.MessageType.Value("LICENSE"): - raise InvalidLicenseMessage( - f"Expecting a LICENSE message, not a " - f"'{SignedMessage.MessageType.Name(license_message.type)}' message." - ) - - r = self.__session.post( - url=f"{self.host}/{self.device_name}/parse_license", - json={ - "session_id": session_id.hex(), - "license_message": base64.b64encode(license_message.SerializeToString()).decode() - } - ).json() - if r["status"] != 200: - raise ValueError(f"Cannot parse License, {r['message']} [{r['status']}]") - - def get_keys(self, session_id: bytes, type_: Optional[Union[int, str]] = None) -> list[Key]: - try: - if isinstance(type_, str): - License.KeyContainer.KeyType.Value(type_) # only test - elif isinstance(type_, int): - type_ = License.KeyContainer.KeyType.Name(type_) - elif type_ is None: - type_ = "ALL" - else: - raise TypeError(f"Expected type_ to be a {License.KeyContainer.KeyType} or int, not {type_!r}") - except ValueError as e: - raise ValueError(f"Could not parse type_ as a {License.KeyContainer.KeyType}, {e}") - - r = self.__session.post( - url=f"{self.host}/{self.device_name}/get_keys/{type_}", - json={ - "session_id": session_id.hex() - } - ).json() - if r["status"] != 200: - raise ValueError(f"Could not get {type_} Keys, {r['message']} [{r['status']}]") - r = r["data"] - - return [ - Key( - type_=key["type"], - kid=Key.kid_to_uuid(bytes.fromhex(key["key_id"])), - key=bytes.fromhex(key["key"]), - permissions=key["permissions"] - ) - for key in r["keys"] - ] - - -__all__ = ("RemoteCdm",) diff --git a/scripts/pywidevine/pywidevine/serve.py b/scripts/pywidevine/pywidevine/serve.py deleted file mode 100644 index 07b0602..0000000 --- a/scripts/pywidevine/pywidevine/serve.py +++ /dev/null @@ -1,458 +0,0 @@ -import base64 -import sys -from pathlib import Path -from typing import Any, Optional, Union - -from aiohttp.typedefs import Handler -from google.protobuf.message import DecodeError - -from pywidevine.pssh import PSSH - -try: - from aiohttp import web -except ImportError: - print( - "Missing the extra dependencies for serve functionality. " - "You may install them under poetry with `poetry install -E serve`, " - "or under pip with `pip install pywidevine[serve]`." - ) - sys.exit(1) - -from pywidevine import __version__ -from pywidevine.cdm import Cdm -from pywidevine.device import Device -from pywidevine.exceptions import (InvalidContext, InvalidInitData, InvalidLicenseMessage, InvalidLicenseType, - InvalidSession, SignatureMismatch, TooManySessions) - -routes = web.RouteTableDef() - - -async def _startup(app: web.Application) -> None: - app["cdms"] = {} - app["config"]["devices"] = { - path.stem: path - for x in app["config"]["devices"] - for path in [Path(x)] - } - for device in app["config"]["devices"].values(): - if not device.is_file(): - raise FileNotFoundError(f"Device file does not exist: {device}") - - -async def _cleanup(app: web.Application) -> None: - app["cdms"].clear() - del app["cdms"] - app["config"].clear() - del app["config"] - - -@routes.get("/") -async def ping(_: Any) -> web.Response: - return web.json_response({ - "status": 200, - "message": "Pong!" - }) - - -@routes.get("/{device}/open") -async def open_(request: web.Request) -> web.Response: - secret_key = request.headers["X-Secret-Key"] - device_name = request.match_info["device"] - user = request.app["config"]["users"][secret_key] - - if device_name not in user["devices"] or device_name not in request.app["config"]["devices"]: - # we don't want to be verbose with the error as to not reveal device names - # by trial and error to users that are not authorized to use them - return web.json_response({ - "status": 403, - "message": f"Device '{device_name}' is not found or you are not authorized to use it." - }, status=403) - - cdm: Optional[Cdm] = request.app["cdms"].get((secret_key, device_name)) - if not cdm: - device = Device.load(request.app["config"]["devices"][device_name]) - cdm = request.app["cdms"][(secret_key, device_name)] = Cdm.from_device(device) - - try: - session_id = cdm.open() - except TooManySessions as e: - return web.json_response({ - "status": 400, - "message": str(e) - }, status=400) - - return web.json_response({ - "status": 200, - "message": "Success", - "data": { - "session_id": session_id.hex(), - "device": { - "system_id": cdm.system_id, - "security_level": cdm.security_level - } - } - }) - - -@routes.get("/{device}/close/{session_id}") -async def close(request: web.Request) -> web.Response: - secret_key = request.headers["X-Secret-Key"] - device_name = request.match_info["device"] - session_id = bytes.fromhex(request.match_info["session_id"]) - - cdm: Optional[Cdm] = request.app["cdms"].get((secret_key, device_name)) - if not cdm: - return web.json_response({ - "status": 400, - "message": f"No Cdm session for {device_name} has been opened yet. No session to close." - }, status=400) - - try: - cdm.close(session_id) - except InvalidSession: - return web.json_response({ - "status": 400, - "message": f"Invalid Session ID '{session_id.hex()}', it may have expired." - }, status=400) - - return web.json_response({ - "status": 200, - "message": f"Successfully closed Session '{session_id.hex()}'." - }) - - -@routes.post("/{device}/set_service_certificate") -async def set_service_certificate(request: web.Request) -> web.Response: - secret_key = request.headers["X-Secret-Key"] - device_name = request.match_info["device"] - - body = await request.json() - for required_field in ("session_id", "certificate"): - if required_field == "certificate": - has_field = required_field in body # it needs the key, but can be empty/null - else: - has_field = body.get(required_field) - if not has_field: - return web.json_response({ - "status": 400, - "message": f"Missing required field '{required_field}' in JSON body." - }, status=400) - - # get session id - session_id = bytes.fromhex(body["session_id"]) - - # get cdm - cdm: Optional[Cdm] = request.app["cdms"].get((secret_key, device_name)) - if not cdm: - return web.json_response({ - "status": 400, - "message": f"No Cdm session for {device_name} has been opened yet. No session to use." - }, status=400) - - # set service certificate - certificate = body.get("certificate") - try: - provider_id = cdm.set_service_certificate(session_id, certificate) - except InvalidSession: - return web.json_response({ - "status": 400, - "message": f"Invalid Session ID '{session_id.hex()}', it may have expired." - }, status=400) - except DecodeError as e: - return web.json_response({ - "status": 400, - "message": f"Invalid Service Certificate, {e}" - }, status=400) - except SignatureMismatch: - return web.json_response({ - "status": 400, - "message": "Signature Validation failed on the Service Certificate, rejecting." - }, status=400) - - return web.json_response({ - "status": 200, - "message": f"Successfully {['set', 'unset'][not certificate]} the Service Certificate.", - "data": { - "provider_id": provider_id - } - }) - - -@routes.post("/{device}/get_service_certificate") -async def get_service_certificate(request: web.Request) -> web.Response: - secret_key = request.headers["X-Secret-Key"] - device_name = request.match_info["device"] - - body = await request.json() - for required_field in ("session_id",): - if not body.get(required_field): - return web.json_response({ - "status": 400, - "message": f"Missing required field '{required_field}' in JSON body." - }, status=400) - - # get session id - session_id = bytes.fromhex(body["session_id"]) - - # get cdm - cdm: Optional[Cdm] = request.app["cdms"].get((secret_key, device_name)) - if not cdm: - return web.json_response({ - "status": 400, - "message": f"No Cdm session for {device_name} has been opened yet. No session to use." - }, status=400) - - # get service certificate - try: - service_certificate = cdm.get_service_certificate(session_id) - except InvalidSession: - return web.json_response({ - "status": 400, - "message": f"Invalid Session ID '{session_id.hex()}', it may have expired." - }, status=400) - - if service_certificate: - service_certificate_b64 = base64.b64encode(service_certificate.SerializeToString()).decode() - else: - service_certificate_b64 = None - - return web.json_response({ - "status": 200, - "message": "Successfully got the Service Certificate.", - "data": { - "service_certificate": service_certificate_b64 - } - }) - - -@routes.post("/{device}/get_license_challenge/{license_type}") -async def get_license_challenge(request: web.Request) -> web.Response: - secret_key = request.headers["X-Secret-Key"] - device_name = request.match_info["device"] - license_type = request.match_info["license_type"] - - body = await request.json() - for required_field in ("session_id", "init_data"): - if not body.get(required_field): - return web.json_response({ - "status": 400, - "message": f"Missing required field '{required_field}' in JSON body." - }, status=400) - - # get session id - session_id = bytes.fromhex(body["session_id"]) - - # get privacy mode flag - privacy_mode = body.get("privacy_mode", True) - - # get cdm - cdm: Optional[Cdm] = request.app["cdms"].get((secret_key, device_name)) - if not cdm: - return web.json_response({ - "status": 400, - "message": f"No Cdm session for {device_name} has been opened yet. No session to use." - }, status=400) - - # enforce service certificate (opt-in) - if request.app["config"].get("force_privacy_mode"): - privacy_mode = True - if not cdm.get_service_certificate(session_id): - return web.json_response({ - "status": 403, - "message": "No Service Certificate set but Privacy Mode is Enforced." - }, status=403) - - # get init data - init_data = PSSH(body["init_data"]) - - # get challenge - try: - license_request = cdm.get_license_challenge( - session_id=session_id, - pssh=init_data, - license_type=license_type, - privacy_mode=privacy_mode - ) - except InvalidSession: - return web.json_response({ - "status": 400, - "message": f"Invalid Session ID '{session_id.hex()}', it may have expired." - }, status=400) - except InvalidInitData as e: - return web.json_response({ - "status": 400, - "message": f"Invalid Init Data, {e}" - }, status=400) - except InvalidLicenseType: - return web.json_response({ - "status": 400, - "message": f"Invalid License Type '{license_type}'" - }, status=400) - - return web.json_response({ - "status": 200, - "message": "Success", - "data": { - "challenge_b64": base64.b64encode(license_request).decode() - } - }, status=200) - - -@routes.post("/{device}/parse_license") -async def parse_license(request: web.Request) -> web.Response: - secret_key = request.headers["X-Secret-Key"] - device_name = request.match_info["device"] - - body = await request.json() - for required_field in ("session_id", "license_message"): - if not body.get(required_field): - return web.json_response({ - "status": 400, - "message": f"Missing required field '{required_field}' in JSON body." - }, status=400) - - # get session id - session_id = bytes.fromhex(body["session_id"]) - - # get cdm - cdm: Optional[Cdm] = request.app["cdms"].get((secret_key, device_name)) - if not cdm: - return web.json_response({ - "status": 400, - "message": f"No Cdm session for {device_name} has been opened yet. No session to use." - }, status=400) - - # parse the license message - try: - cdm.parse_license(session_id, body["license_message"]) - except InvalidSession: - return web.json_response({ - "status": 400, - "message": f"Invalid Session ID '{session_id.hex()}', it may have expired." - }, status=400) - except InvalidLicenseMessage as e: - return web.json_response({ - "status": 400, - "message": f"Invalid License Message, {e}" - }, status=400) - except InvalidContext as e: - return web.json_response({ - "status": 400, - "message": f"Invalid Context, {e}" - }, status=400) - except SignatureMismatch: - return web.json_response({ - "status": 400, - "message": "Signature Validation failed on the License Message, rejecting." - }, status=400) - - return web.json_response({ - "status": 200, - "message": "Successfully parsed and loaded the Keys from the License message." - }) - - -@routes.post("/{device}/get_keys/{key_type}") -async def get_keys(request: web.Request) -> web.Response: - secret_key = request.headers["X-Secret-Key"] - device_name = request.match_info["device"] - - body = await request.json() - for required_field in ("session_id",): - if not body.get(required_field): - return web.json_response({ - "status": 400, - "message": f"Missing required field '{required_field}' in JSON body." - }, status=400) - - # get session id - session_id = bytes.fromhex(body["session_id"]) - - # get key type - key_type: Optional[str] = request.match_info["key_type"] - if key_type == "ALL": - key_type = None - - # get cdm - cdm = request.app["cdms"].get((secret_key, device_name)) - if not cdm: - return web.json_response({ - "status": 400, - "message": f"No Cdm session for {device_name} has been opened yet. No session to use." - }, status=400) - - # get keys - try: - keys = cdm.get_keys(session_id, key_type) - except InvalidSession: - return web.json_response({ - "status": 400, - "message": f"Invalid Session ID '{session_id.hex()}', it may have expired." - }, status=400) - except ValueError as e: - return web.json_response({ - "status": 400, - "message": f"The Key Type value '{key_type}' is invalid, {e}" - }, status=400) - - # get the keys in json form - keys_json = [ - { - "key_id": key.kid.hex, - "key": key.key.hex(), - "type": key.type, - "permissions": key.permissions, - } - for key in keys - if not key_type or key.type == key_type - ] - - return web.json_response({ - "status": 200, - "message": "Success", - "data": { - "keys": keys_json - } - }) - - -@web.middleware -async def authentication(request: web.Request, handler: Handler) -> web.Response: - secret_key = request.headers.get("X-Secret-Key") - - if request.path != "/" and not secret_key: - request.app.logger.debug(f"{request.remote} did not provide authorization.") - response = web.json_response({ - "status": "401", - "message": "Secret Key is Empty." - }, status=401) - elif request.path != "/" and secret_key not in request.app["config"]["users"]: - request.app.logger.debug(f"{request.remote} failed authentication with '{secret_key}'.") - response = web.json_response({ - "status": "401", - "message": "Secret Key is Invalid, the Key is case-sensitive." - }, status=401) - else: - try: - response = await handler(request) # type: ignore[assignment] - except web.HTTPException as e: - request.app.logger.error(f"An unexpected error has occurred, {e}") - response = web.json_response({ - "status": 500, - "message": e.reason - }, status=500) - - response.headers.update({ - "Server": f"https://github.com/devine-dl/pywidevine serve v{__version__}" - }) - - return response - - -def run(config: dict, host: Optional[Union[str, web.HostSequence]] = None, port: Optional[int] = None) -> None: - app = web.Application(middlewares=[authentication]) - app.on_startup.append(_startup) - app.on_cleanup.append(_cleanup) - app.add_routes(routes) - app["config"] = config - web.run_app(app, host=host, port=port) diff --git a/scripts/pywidevine/pywidevine/session.py b/scripts/pywidevine/pywidevine/session.py deleted file mode 100644 index 7cb816f..0000000 --- a/scripts/pywidevine/pywidevine/session.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Optional - -from Crypto.Random import get_random_bytes - -from pywidevine.key import Key -from pywidevine.license_protocol_pb2 import SignedDrmCertificate - - -class Session: - def __init__(self, number: int): - self.number = number - self.id = get_random_bytes(16) - self.service_certificate: Optional[SignedDrmCertificate] = None - self.context: dict[bytes, tuple[bytes, bytes]] = {} - self.keys: list[Key] = [] - - -__all__ = ("Session",) diff --git a/scripts/pywidevine/pywidevine/utils.py b/scripts/pywidevine/pywidevine/utils.py deleted file mode 100644 index 6556d3e..0000000 --- a/scripts/pywidevine/pywidevine/utils.py +++ /dev/null @@ -1,12 +0,0 @@ -import shutil -from pathlib import Path -from typing import Optional - - -def get_binary_path(*names: str) -> Optional[Path]: - """Get the path of the first found binary name.""" - for name in names: - path = shutil.which(name) - if path: - return Path(path) - return None diff --git a/the_office.py b/the_office.py new file mode 100644 index 0000000..6d30c9c --- /dev/null +++ b/the_office.py @@ -0,0 +1,21 @@ +import subprocess +import os + +temp = r"E:\Downloads\WV_rippers\tools\temp" +output = r"E:\Downloads\CanalPlus" +mp4decrypt = r"E:\Downloads\WV_rippers\tools\mp4decrypt.exe" +mkvpropedit = r"E:\Programy\MKVToolNix\mkvpropedit.exe" +Nm3u8DLRE = r"E:\Downloads\WV_rippers\tools\N_m3u8DL-RE.exe" +video_quality = "best" +audio_lang = "pol" +subs_lang = "pol" +name = "The.Office.PL.EPISODE.1080p.ANALplus.WEB-DL.AAC2.0.h264-TRad" + + +def download_and_decrypt(mpd, deckey, episode): + name_fix = name.replace('EPISODE', episode) + subprocess.call([Nm3u8DLRE, mpd, '--save-dir', output, '--save-name', name_fix, '--tmp-dir', temp, '--key', deckey, '-sv', video_quality, '-sa', 'lang='+audio_lang, '-ss', 'lang='+subs_lang, '-M', 'format=mkv', '--decryption-binary-path', mp4decrypt]) + +download_and_decrypt("https://r.cdn-ncplus.pl/vod/store01/BEL_70005415/_/hd4-hssdrm02.ism/manifest", "1c71615473c849aabf4ff6ce6cc613ca:7eeab8416988c2e5eee2a6ad1b92426c", "S03E00") + +# download_and_decrypt("", "", "S01E0") \ No newline at end of file diff --git a/venv.cmd b/venv.cmd deleted file mode 100644 index 9ff4941..0000000 --- a/venv.cmd +++ /dev/null @@ -1 +0,0 @@ -cmd /k .\.venv\Scripts\activate.bat \ No newline at end of file diff --git a/vinetrimmer/commands/dl.py b/vinetrimmer/commands/dl.py index 871c3e4..3e95cd9 100644 --- a/vinetrimmer/commands/dl.py +++ b/vinetrimmer/commands/dl.py @@ -8,693 +8,657 @@ import sys import traceback from http.cookiejar import MozillaCookieJar -import time import click import requests from appdirs import AppDirs from langcodes import Language from pymediainfo import MediaInfo -from pathlib import Path from vinetrimmer import services from vinetrimmer.config import Config, config, credentials, directories, filenames from vinetrimmer.objects import AudioTrack, Credential, TextTrack, Title, Titles, VideoTrack -from vinetrimmer.objects.tracks import Track from vinetrimmer.objects.vaults import InsertResult, Vault, Vaults -from vinetrimmer.utils import is_close_match +from vinetrimmer.utils import Cdm, is_close_match from vinetrimmer.utils.click import (AliasedGroup, ContextData, acodec_param, language_param, quality_param, - range_param, vcodec_param, wanted_param) + range_param, vcodec_param, wanted_param) from vinetrimmer.utils.collections import as_list, merge_dict from vinetrimmer.utils.io import load_yaml -from pywidevine import Device, Cdm, RemoteCdm - +from vinetrimmer.utils.widevine.device import LocalDevice, RemoteDevice from vinetrimmer.vendor.pymp4.parser import Box from pyplayready.cdm import Cdm as CdmPr -from pyplayready import Device as DevicePR -from pyplayready.system.pssh import PSSH -from pyplayready.crypto.ecc_key import ECCKey -from pyplayready.system.bcert import CertificateChain, Certificate -from Crypto.Random import get_random_bytes +from pyplayready.device import Device +from pyplayready.pssh import PSSH - -def reprovision_device(prd_path) -> None: +def get_cdm(service, profile=None, cdm_name=None): """ - Reprovision a Playready Device (.prd) by creating a new leaf certificate and new encryption/signing keys. - Will override the device if an output path or directory is not specified - - Only works on PRD Devices of v3 or higher + Get CDM Device (either remote or local) for a specified service. + Raises a ValueError if there's a problem getting a CDM. """ - prd_path = Path(prd_path) - if not prd_path.is_file(): - raise Exception("prd_path: Not a path to a file, or it doesn't exist.") + if not cdm_name: + cdm_name = config.cdm.get(service) or config.cdm.get("default") + if not cdm_name: + raise ValueError("A CDM to use wasn't listed in the vinetrimmer.yml config") + if isinstance(cdm_name, dict): + if not profile: + raise ValueError("CDM config is mapped for profiles, but no profile was chosen") + cdm_name = cdm_name.get(profile) or config.cdm.get("default") + if not cdm_name: + raise ValueError(f"A CDM to use was not mapped for the profile {profile}") + if "sl2000" or "sl3000" in cdm_name.lower(): + + device_pr = Device.load(os.path.join(directories.devices, f"{cdm_name}.prd")) + return device_pr + try: + + return LocalDevice.load(os.path.join(directories.devices, f"{cdm_name}.wvd")) + except FileNotFoundError: + dirs = [ + os.path.join(directories.devices, cdm_name), + os.path.join(AppDirs("pywidevine", False).user_data_dir, "devices", cdm_name), + os.path.join(AppDirs("pywidevine", False).site_data_dir, "devices", cdm_name), + ] - device = DevicePR.load(prd_path) + for d in dirs: + try: + return LocalDevice.from_dir(d) + except FileNotFoundError: + pass - if device.group_key is None: - raise Exception("Device does not support reprovisioning, re-create it or use a Device with a version of 3 or higher") + cdm_api = next(iter(x for x in config.cdm_api if x["name"] == cdm_name), None) + if cdm_api: + return RemoteDevice(**cdm_api) - device.group_certificate.remove(0) - - encryption_key = ECCKey.generate() - signing_key = ECCKey.generate() - - device.encryption_key = encryption_key - device.signing_key = signing_key - - new_certificate = Certificate.new_leaf_cert( - cert_id=get_random_bytes(16), - security_level=device.group_certificate.get_security_level(), - client_id=get_random_bytes(16), - signing_key=signing_key, - encryption_key=encryption_key, - group_key=device.group_key, - parent=device.group_certificate - ) - device.group_certificate.prepend(new_certificate) - - prd_path.parent.mkdir(parents=True, exist_ok=True) - prd_path.write_bytes(device.dumps()) - - -def get_cdm(log, service, profile=None, cdm_name=None): - """ - Get CDM Device (either remote or local) for a specified service. - Raises a ValueError if there's a problem getting a CDM. - """ - if not cdm_name: - cdm_name = config.cdm.get(service) or config.cdm.get("default") - if not cdm_name: - raise ValueError("A CDM to use wasn't listed in the vinetrimmer.yml config") - if isinstance(cdm_name, dict): - if not profile: - raise ValueError("CDM config is mapped for profiles, but no profile was chosen") - cdm_name = cdm_name.get(profile) or config.cdm.get("default") - if not cdm_name: - raise ValueError(f"A CDM to use was not mapped for the profile {profile}") - - try: - try: - device = Device.load(os.path.join(directories.devices, f"{cdm_name}.wvd")) - except: - device_path = os.path.abspath(os.path.join(directories.devices, f"{cdm_name}.prd")) - if ( int( time.time() ) - int( os.path.getmtime( device_path ) ) ) > 600000: #roughly a week - try: - reprovision_device(device_path) - log.info(f" + Reprovisioned Playready Device (.prd) file, {cdm_name}") - except Exception as e: - log.warning(f"Reprovision Failed - {e}") - device = DevicePR.load(device_path) - return device - except FileNotFoundError: - try: - return Device.from_dir(os.path.join(directories.devices, cdm_name)) - except: - pass - - cdm_api = next(iter(x for x in config.cdm_api if x["name"] == cdm_name), None) - if cdm_api: - try: - return RemoteCdm(**cdm_api) - except: - from vinetrimmer.utils.widevine.device import RemoteDevice - return RemoteDevice(**cdm_api) # seller distributed some wack version of serve in pywidevine - - raise ValueError(f"Device {cdm_name!r} not found") + raise ValueError(f"Device {cdm_name!r} not found") def get_service_config(service): - """Get both service config and service secrets as one merged dictionary.""" - service_config = load_yaml(filenames.service_config.format(service=service.lower())) + """Get both service config and service secrets as one merged dictionary.""" + service_config = load_yaml(filenames.service_config.format(service=service.lower())) - user_config = (load_yaml(filenames.user_service_config.format(service=service.lower())) - or load_yaml(filenames.user_service_config.format(service=service))) + user_config = (load_yaml(filenames.user_service_config.format(service=service.lower())) + or load_yaml(filenames.user_service_config.format(service=service))) - if user_config: - merge_dict(service_config, user_config) + if user_config: + merge_dict(service_config, user_config) - return service_config + return service_config def get_profile(service): - """ - Get the default profile for a service from the config. - """ - profile = config.profiles.get(service) - if profile is False: - return None # auth-less service if `false` in config - if not profile: - profile = config.profiles.get("default") - if not profile: - raise ValueError(f"No profile has been defined for '{service}' in the config.") + """ + Get the default profile for a service from the config. + """ + profile = config.profiles.get(service) + if profile is False: + return None # auth-less service if `false` in config + if not profile: + profile = config.profiles.get("default") + if not profile: + raise ValueError(f"No profile has been defined for '{service}' in the config.") - return profile + return profile def get_cookie_jar(service, profile): - """Get the profile's cookies if available.""" - cookie_file = os.path.join(directories.cookies, service.lower(), f"{profile}.txt") - if not os.path.isfile(cookie_file): - cookie_file = os.path.join(directories.cookies, service, f"{profile}.txt") - if os.path.isfile(cookie_file): - cookie_jar = MozillaCookieJar(cookie_file) - with open(cookie_file, "r+", encoding="utf-8") as fd: - unescaped = html.unescape(fd.read()) - fd.seek(0) - fd.truncate() - fd.write(unescaped) - cookie_jar.load(ignore_discard=True, ignore_expires=True) - return cookie_jar - return None + """Get the profile's cookies if available.""" + cookie_file = os.path.join(directories.cookies, service.lower(), f"{profile}.txt") + if not os.path.isfile(cookie_file): + cookie_file = os.path.join(directories.cookies, service, f"{profile}.txt") + if os.path.isfile(cookie_file): + cookie_jar = MozillaCookieJar(cookie_file) + with open(cookie_file, "r+", encoding="utf-8") as fd: + unescaped = html.unescape(fd.read()) + fd.seek(0) + fd.truncate() + fd.write(unescaped) + cookie_jar.load(ignore_discard=True, ignore_expires=True) + return cookie_jar + return None def get_credentials(service, profile="default"): - """Get the profile's credentials if available.""" - cred = credentials.get(service, {}) + """Get the profile's credentials if available.""" + cred = credentials.get(service, {}) - if isinstance(cred, dict): - cred = cred.get(profile) - elif profile != "default": - return None + if isinstance(cred, dict): + cred = cred.get(profile) + elif profile != "default": + return None - if cred: - if isinstance(cred, list): - return Credential(*cred) - else: - return Credential.loads(cred) + if cred: + if isinstance(cred, list): + return Credential(*cred) + else: + return Credential.loads(cred) @click.group(name="dl", short_help="Download from a service.", cls=AliasedGroup, context_settings=dict( - help_option_names=["-?", "-h", "--help"], - max_content_width=116, # max PEP8 line-width, -4 to adjust for initial indent - default_map=config.arguments + help_option_names=["-?", "-h", "--help"], + max_content_width=116, # max PEP8 line-width, -4 to adjust for initial indent + default_map=config.arguments )) @click.option("--debug", is_flag=True, hidden=True) # Handled by vinetrimmer.py @click.option("-p", "--profile", type=str, default=None, - help="Profile to use when multiple profiles are defined for a service.") + help="Profile to use when multiple profiles are defined for a service.") @click.option("-q", "--quality", callback=quality_param, default=None, - help="Download Resolution, defaults to best available.") + help="Download Resolution, defaults to best available.") @click.option("-v", "--vcodec", callback=vcodec_param, default="H264", - help="Video Codec, defaults to H264.") + help="Video Codec, defaults to H264.") @click.option("-a", "--acodec", callback=acodec_param, default=None, - help="Audio Codec") + help="Audio Codec") @click.option("-vb", "--vbitrate", "vbitrate", type=int, - default=None, - help="Video Bitrate, defaults to Max.") + default=None, + help="Video Bitrate, defaults to Max.") @click.option("-ab", "--abitrate", "abitrate", type=int, - default=None, - help="Audio Bitrate, defaults to Max.") + default=None, + help="Audio Bitrate, defaults to Max.") @click.option("-aa", "--atmos", is_flag=True, default=False, - help="Prefer Atmos Audio") + help="Prefer Atmos Audio") @click.option("-r", "--range", "range_", callback=range_param, default="SDR", - help="Video Color Range, defaults to SDR.") + help="Video Color Range, defaults to SDR.") @click.option("-w", "--wanted", callback=wanted_param, default=None, - help="Wanted episodes, e.g. `S01-S05,S07`, `S01E01-S02E03`, `S02-S02E03`, e.t.c, defaults to all.") + help="Wanted episodes, e.g. `S01-S05,S07`, `S01E01-S02E03`, `S02-S02E03`, e.t.c, defaults to all.") @click.option("-al", "--alang", callback=language_param, default="orig", - help="Language wanted for audio.") + help="Language wanted for audio.") @click.option("-sl", "--slang", callback=language_param, default="all", - help="Language wanted for subtitles.") + help="Language wanted for subtitles.") @click.option("--proxy", type=str, default=None, - help="Proxy URI to use. If a 2-letter country is provided, it will try get a proxy from the config.") + help="Proxy URI to use. If a 2-letter country is provided, it will try get a proxy from the config.") @click.option("-A", "--audio-only", is_flag=True, default=False, - help="Only download audio tracks.") + help="Only download audio tracks.") @click.option("-S", "--subs-only", is_flag=True, default=False, - help="Only download subtitle tracks.") + help="Only download subtitle tracks.") @click.option("-C", "--chapters-only", is_flag=True, default=False, - help="Only download chapters.") + help="Only download chapters.") @click.option("-ns", "--no-subs", is_flag=True, default=False, - help="Do not download subtitle tracks.") + help="Do not download subtitle tracks.") @click.option("-na", "--no-audio", is_flag=True, default=False, - help="Do not download audio tracks.") + help="Do not download audio tracks.") @click.option("-nv", "--no-video", is_flag=True, default=False, - help="Do not download video tracks.") + help="Do not download video tracks.") @click.option("-nc", "--no-chapters", is_flag=True, default=False, - help="Do not download chapters tracks.") + help="Do not download chapters tracks.") @click.option("-ad", "--audio-description", is_flag=True, default=False, - help="Download audio description tracks.") + help="Download audio description tracks.") @click.option("--list", "list_", is_flag=True, default=False, - help="Skip downloading and list available tracks and what tracks would have been downloaded.") + help="Skip downloading and list available tracks and what tracks would have been downloaded.") @click.option("--selected", is_flag=True, default=False, - help="List selected tracks and what tracks are downloaded.") + help="List selected tracks and what tracks are downloaded.") @click.option("--cdm", type=str, default=None, - help="Override the CDM that will be used for decryption.") + help="Override the CDM that will be used for decryption.") @click.option("--keys", is_flag=True, default=False, - help="Skip downloading, retrieve the decryption keys (via CDM or Key Vaults) and print them.") + help="Skip downloading, retrieve the decryption keys (via CDM or Key Vaults) and print them.") @click.option("--cache", is_flag=True, default=False, - help="Disable the use of the CDM and only retrieve decryption keys from Key Vaults. " - "If a needed key is unable to be retrieved from any Key Vaults, the title is skipped.") + help="Disable the use of the CDM and only retrieve decryption keys from Key Vaults. " + "If a needed key is unable to be retrieved from any Key Vaults, the title is skipped.") @click.option("--no-cache", is_flag=True, default=False, - help="Disable the use of Key Vaults and only retrieve decryption keys from the CDM.") + help="Disable the use of Key Vaults and only retrieve decryption keys from the CDM.") @click.option("--no-proxy", is_flag=True, default=False, - help="Force disable all proxy use.") + help="Force disable all proxy use.") @click.option("-nm", "--no-mux", is_flag=True, default=False, - help="Do not mux the downloaded and decrypted tracks.") + help="Do not mux the downloaded and decrypted tracks.") @click.option("--mux", is_flag=True, default=False, - help="Force muxing when using --audio-only/--subs-only/--chapters-only.") + help="Force muxing when using --audio-only/--subs-only/--chapters-only.") @click.pass_context def dl(ctx, profile, cdm, *_, **__): - log = logging.getLogger("dl") + log = logging.getLogger("dl") - service = ctx.params.get("service_name") or services.get_service_key(ctx.invoked_subcommand) - if not service: - log.exit(" - Unable to find service") + service = ctx.params.get("service_name") or services.get_service_key(ctx.invoked_subcommand) + if not service: + log.exit(" - Unable to find service") - profile = profile or get_profile(service) - service_config = get_service_config(service) - vaults = [] - for vault in config.key_vaults: - try: - vaults.append(Config.load_vault(vault)) - except Exception as e: - log.error(f" - Failed to load vault {vault['name']!r}: {e}") - vaults = Vaults(vaults, service=service) - local_vaults = sum(v.type == Vault.Types.LOCAL for v in vaults) - remote_vaults = sum(v.type == Vault.Types.REMOTE for v in vaults) - log.info(f" + {local_vaults} Local Vault{'' if local_vaults == 1 else 's'}") - log.info(f" + {remote_vaults} Remote Vault{'' if remote_vaults == 1 else 's'}") + profile = profile or get_profile(service) + service_config = get_service_config(service) + vaults = [] + for vault in config.key_vaults: + try: + vaults.append(Config.load_vault(vault)) + except Exception as e: + log.error(f" - Failed to load vault {vault['name']!r}: {e}") + vaults = Vaults(vaults, service=service) + local_vaults = sum(v.type == Vault.Types.LOCAL for v in vaults) + remote_vaults = sum(v.type == Vault.Types.REMOTE for v in vaults) + log.info(f" + {local_vaults} Local Vault{'' if local_vaults == 1 else 's'}") + log.info(f" + {remote_vaults} Remote Vault{'' if remote_vaults == 1 else 's'}") - try: - device = get_cdm(log, service, profile, cdm) - except ValueError as e: - raise log.exit(f" - {e}") + try: + device = get_cdm(service, profile, cdm) + except ValueError as e: + raise log.exit(f" - {e}") + device_name = device.group_certificate.get_name() if "sl3000" or "sl2000" in device.get_name() else device.system_id + log.info(f" + Loaded {device.__class__.__name__}: {device_name} (L{device.security_level})") + cdm = CdmPr.from_device(device) if "sl3000" or "sl2000" in device.get_name() else Cdm(device) - device_name = device.system_id if "set_service_certificate" in dir(device) else device.get_name() - log.info(f" + Loaded {device.__class__.__name__}: {device_name} (L{device.security_level})") - cdm = Cdm(device) if "set_service_certificate" in dir(device) else CdmPr.from_device(device) + if profile: + cookies = get_cookie_jar(service, profile) + credentials = get_credentials(service, profile) + if not cookies and not credentials and service_config.get("needs_auth", True): + raise log.exit(f" - Profile {profile!r} has no cookies or credentials") + else: + cookies = None + credentials = None - if profile: - cookies = get_cookie_jar(service, profile) - credentials = get_credentials(service, profile) - if not cookies and not credentials and service_config.get("needs_auth", True): - raise log.exit(f" - Profile {profile!r} has no cookies or credentials") - else: - cookies = None - credentials = None - - ctx.obj = ContextData( - config=service_config, - vaults=vaults, - cdm=cdm, - profile=profile, - cookies=cookies, - credentials=credentials, - ) + ctx.obj = ContextData( + config=service_config, + vaults=vaults, + cdm=cdm, + profile=profile, + cookies=cookies, + credentials=credentials, + ) @dl.result_callback() @click.pass_context def result(ctx, service, quality, range_, wanted, alang, slang, audio_only, subs_only, chapters_only, audio_description, - list_, keys, cache, no_cache, no_subs, no_audio, no_video, no_chapters, atmos, vbitrate: int, abitrate: int, no_mux, mux, selected, *_, **__): - def ccextractor(): - log.info("Extracting EIA-608 captions from stream with CCExtractor") - track_id = f"ccextractor-{track.id}" - # TODO: Is it possible to determine the language of EIA-608 captions? - cc_lang = track.language - try: - cc = track.ccextractor( - track_id=track_id, - out_path=filenames.subtitles.format(id=track_id, language_code=cc_lang), - language=cc_lang, - original=False, - ) - except EnvironmentError: - log.warning(" - CCExtractor not found, cannot extract captions") - else: - if cc: - title.tracks.add(cc) - log.info(" + Extracted") - else: - log.info(" + No captions found") + list_, keys, cache, no_cache, no_subs, no_audio, no_video, no_chapters, atmos, vbitrate: int, abitrate: int, no_mux, mux, selected, *_, **__): + def ccextractor(): + log.info("Extracting EIA-608 captions from stream with CCExtractor") + track_id = f"ccextractor-{track.id}" + # TODO: Is it possible to determine the language of EIA-608 captions? + cc_lang = track.language + try: + cc = track.ccextractor( + track_id=track_id, + out_path=filenames.subtitles.format(id=track_id, language_code=cc_lang), + language=cc_lang, + original=False, + ) + except EnvironmentError: + log.warning(" - CCExtractor not found, cannot extract captions") + else: + if cc: + title.tracks.add(cc) + log.info(" + Extracted") + else: + log.info(" + No captions found") - log = service.log + log = service.log - service_name = service.__class__.__name__ + service_name = service.__class__.__name__ - log.info("Retrieving Titles") - try: - titles = Titles(as_list(service.get_titles())) - except requests.HTTPError as e: - log.debug(traceback.format_exc()) - raise log.exit(f" - HTTP Error {e.response.status_code}: {e.response.reason}") - if not titles: - raise log.exit(" - No titles returned!") - titles.order() - titles.print() + log.info("Retrieving Titles") + try: + titles = Titles(as_list(service.get_titles())) + except requests.HTTPError as e: + log.debug(traceback.format_exc()) + raise log.exit(f" - HTTP Error {e.response.status_code}: {e.response.reason}") + if not titles: + raise log.exit(" - No titles returned!") + titles.order() + titles.print() - for title in titles.with_wanted(wanted): - if title.type == Title.Types.TV: - log.info("Getting tracks for {title} S{season:02}E{episode:02}{name} [{id}]".format( - title=title.name, - season=title.season or 0, - episode=title.episode or 0, - name=f" - {title.episode_name}" if title.episode_name else "", - id=title.id, - )) - else: - log.info("Getting tracks for {title}{year} [{id}]".format( - title=title.name, - year=f" ({title.year})" if title.year else "", - id=title.id, - )) + for title in titles.with_wanted(wanted): + if title.type == Title.Types.TV: + log.info("Getting tracks for {title} S{season:02}E{episode:02}{name} [{id}]".format( + title=title.name, + season=title.season or 0, + episode=title.episode or 0, + name=f" - {title.episode_name}" if title.episode_name else "", + id=title.id, + )) + else: + log.info("Getting tracks for {title}{year} [{id}]".format( + title=title.name, + year=f" ({title.year})" if title.year else "", + id=title.id, + )) - try: - title.tracks.add(service.get_tracks(title), warn_only=True) - title.tracks.add(service.get_chapters(title)) - #if not next((x for x in title.tracks.videos if x.language.language in (v_lang or lang)), None) and title.tracks.videos: - # lang = [title.tracks.videos[0].language["language"]] - # log.info("Defaulting language to {lang} for tracks".format(lang=lang[0].upper())) - except requests.HTTPError as e: - log.debug(traceback.format_exc()) - raise log.exit(f" - HTTP Error {e.response.status_code}: {e.response.reason}") - title.tracks.sort_videos() - title.tracks.sort_audios(by_language=alang) - title.tracks.sort_subtitles(by_language=slang) - title.tracks.sort_chapters() + try: + title.tracks.add(service.get_tracks(title), warn_only=True) + title.tracks.add(service.get_chapters(title)) + #if not next((x for x in title.tracks.videos if x.language.language in (v_lang or lang)), None) and title.tracks.videos: + # lang = [title.tracks.videos[0].language["language"]] + # log.info("Defaulting language to {lang} for tracks".format(lang=lang[0].upper())) + except requests.HTTPError as e: + log.debug(traceback.format_exc()) + raise log.exit(f" - HTTP Error {e.response.status_code}: {e.response.reason}") + title.tracks.sort_videos() + title.tracks.sort_audios(by_language=alang) + title.tracks.sort_subtitles(by_language=slang) + title.tracks.sort_chapters() - for track in title.tracks: - if track.language == Language.get("none"): - track.language = title.original_lang - track.is_original_lang = is_close_match(track.language, [title.original_lang]) + for track in title.tracks: + if track.language == Language.get("none"): + track.language = title.original_lang + track.is_original_lang = is_close_match(track.language, [title.original_lang]) - if not list(title.tracks): - log.error(" - No tracks returned!") - continue - if not selected: - log.info("> All Tracks:") - title.tracks.print() + if not list(title.tracks): + log.error(" - No tracks returned!") + continue + if not selected: + log.info("> All Tracks:") + title.tracks.print() - try: - #title.tracks.select_videos(by_quality=quality, by_range=range_, one_only=True) - title.tracks.select_videos(by_quality=quality, by_vbitrate=vbitrate, by_range=range_, one_only=True) - title.tracks.select_audios(by_language=alang, by_bitrate=abitrate, with_descriptive=audio_description) - # title.tracks.select_audios(by_language=alang, with_descriptive=audio_description) - title.tracks.select_subtitles(by_language=slang, with_forced=True) - except ValueError as e: - log.error(f" - {e}") - continue + try: + #title.tracks.select_videos(by_quality=quality, by_range=range_, one_only=True) + title.tracks.select_videos(by_quality=quality, by_vbitrate=vbitrate, by_range=range_, one_only=True) + title.tracks.select_audios(by_language=alang, by_bitrate=abitrate, with_descriptive=audio_description) + # title.tracks.select_audios(by_language=alang, with_descriptive=audio_description) + title.tracks.select_subtitles(by_language=slang, with_forced=True) + except ValueError as e: + log.error(f" - {e}") + continue - if no_video: - title.tracks.videos.clear() - if no_audio: - title.tracks.audios.clear() - if no_subs: - title.tracks.subtitles.clear() - if no_chapters: - title.tracks.chapters.clear() - if audio_only or subs_only or chapters_only: - title.tracks.videos.clear() - if audio_only: - if not subs_only: - title.tracks.subtitles.clear() - if not chapters_only: - title.tracks.chapters.clear() - elif subs_only: - if not audio_only: - title.tracks.audios.clear() - if not chapters_only: - title.tracks.chapters.clear() - elif chapters_only: - if not audio_only: - title.tracks.audios.clear() - if not subs_only: - title.tracks.subtitles.clear() + if no_video: + title.tracks.videos.clear() + + if no_audio: + title.tracks.audios.clear() + + if no_subs: + title.tracks.subtitles.clear() + + if no_chapters: + title.tracks.chapters.clear() + + if audio_only or subs_only or chapters_only: + title.tracks.videos.clear() + if audio_only: + if not subs_only: + title.tracks.subtitles.clear() + if not chapters_only: + title.tracks.chapters.clear() + elif subs_only: + if not audio_only: + title.tracks.audios.clear() + if not chapters_only: + title.tracks.chapters.clear() + elif chapters_only: + if not audio_only: + title.tracks.audios.clear() + if not subs_only: + title.tracks.subtitles.clear() - if not mux: - no_mux = True + if not mux: + no_mux = True - log.info("> Selected Tracks:") - title.tracks.print() - + log.info("> Selected Tracks:") + title.tracks.print() + - if list_: - continue # only wanted to see what tracks were available and chosen + if list_: + continue # only wanted to see what tracks were available and chosen - skip_title = False - for track in title.tracks: - if not keys: - log.info(f"Downloading: {track}") - if (service_name == "AppleTVPlus" or service_name == "iTunes") and "VID" in str(track): - track.encrypted = True - if track.encrypted: - if not track.get_pssh(service.session): - raise log.exit(" - Failed to get PSSH") - log.info(f" + PSSH: {track.pssh}") - if not track.get_kid(service.session): - raise log.exit(" - Failed to get KID") - log.info(f" + KID: {track.kid}") - if not keys: - if track.needs_proxy: - proxy = next(iter(service.session.proxies.values()), None) - else: - proxy = None - track.download(directories.temp, headers=service.session.headers, proxy=proxy) - log.info(" + Downloaded") - if isinstance(track, VideoTrack) and track.needs_ccextractor_first and not no_subs: - ccextractor() - if track.encrypted: - log.info("Decrypting...") - if track.key: - log.info(f" + KEY: {track.key} (Static)") - elif not no_cache: - track.key, vault_used = ctx.obj.vaults.get(track.kid, title.id) - if track.key: - log.info(f" + KEY: {track.key} (From {vault_used.name} {vault_used.type.name} Key Vault)") - for vault in ctx.obj.vaults.vaults: - if vault == vault_used: - continue - result = ctx.obj.vaults.insert_key( - vault, service_name.lower(), track.kid, track.key, title.id, commit=True - ) - if result == InsertResult.SUCCESS: - log.info(f" + Cached to {vault} vault") - elif result == InsertResult.ALREADY_EXISTS: - log.info(f" + Already exists in {vault} vault") - if not track.key: - if cache: - skip_title = True - break - if "common_privacy_cert" in dir(ctx.obj.cdm): - session_id = ctx.obj.cdm.open(track.pssh) - log.info(f"CDM Session ID - {session_id.hex()}") - ctx.obj.cdm.set_service_certificate( - session_id, - service.certificate( - challenge=ctx.obj.cdm.service_certificate_challenge, - title=title, - track=track, - session_id=session_id - ) or ctx.obj.cdm.common_privacy_cert - ) - ctx.obj.cdm.parse_license( - session_id, - service.license( - challenge=ctx.obj.cdm.get_license_challenge(session_id), - title=title, - track=track, - session_id=session_id - ) - ) - else: - session_id = ctx.obj.cdm.open() - log.info(f"CDM Session ID - {session_id.hex()}") - wrm_header = PSSH(track.pssh).get_wrm_headers()[0] - challenge = ctx.obj.cdm.get_license_challenge(session_id, wrm_header) - #log.info(f"{wrm_header} --> {challenge}") - licence = service.license( - challenge=challenge, - title=title, - track=track, - ) - log.debug(licence) - ctx.obj.cdm.parse_license( - session_id, - licence # expects the XML License not base64 encoded str. - ) - - - content_keys = [ - (x.kid, x.key) for x in ctx.obj.cdm.get_keys(session_id, content_only=True) - ] if "common_privacy_cert" in dir(ctx.obj.cdm) else [ - (str(x.key_id).replace("-", ""), x.key.hex()) for x in ctx.obj.cdm.get_keys(session_id) - ] + skip_title = False + for track in title.tracks: + if not keys: + log.info(f"Downloading: {track}") + if (service_name == "AppleTVPlus" or service_name == "iTunes") and "VID" in str(track): + track.encrypted = True + if track.encrypted: + if not track.get_pssh(service.session): + raise log.exit(" - Failed to get PSSH") + log.info(f" + PSSH: {track.pssh}") + if not track.get_kid(service.session): + raise log.exit(" - Failed to get KID") + log.info(f" + KID: {track.kid}") + if not keys: + if track.needs_proxy: + proxy = next(iter(service.session.proxies.values()), None) + else: + proxy = None + track.download(directories.temp, headers=service.session.headers, proxy=proxy) + log.info(" + Downloaded") + if isinstance(track, VideoTrack) and track.needs_ccextractor_first and not no_subs: + ccextractor() + if track.encrypted: + log.info("Decrypting...") + if track.key: + log.info(f" + KEY: {track.key} (Static)") + elif not no_cache: + track.key, vault_used = ctx.obj.vaults.get(track.kid, title.id) + if track.key: + log.info(f" + KEY: {track.key} (From {vault_used.name} {vault_used.type.name} Key Vault)") + for vault in ctx.obj.vaults.vaults: + if vault == vault_used: + continue + result = ctx.obj.vaults.insert_key( + vault, service_name.lower(), track.kid, track.key, title.id, commit=True + ) + if result == InsertResult.SUCCESS: + log.info(f" + Cached to {vault} vault") + elif result == InsertResult.ALREADY_EXISTS: + log.info(f" + Already exists in {vault} vault") + if not track.key: + if cache: + skip_title = True + break + try: + if "common_privacy_cert" in dir(ctx.obj.cdm): + session_id = ctx.obj.cdm.open(track.pssh) + log.info(f"CDM Session ID - {session_id.hex()}") + ctx.obj.cdm.set_service_certificate( + session_id, + service.certificate( + challenge=ctx.obj.cdm.service_certificate_challenge, + title=title, + track=track, + session_id=session_id + ) or ctx.obj.cdm.common_privacy_cert + ) + ctx.obj.cdm.parse_license( + session_id, + service.license( + challenge=ctx.obj.cdm.get_license_challenge(session_id), + title=title, + track=track, + session_id=session_id + ) + ) + else: + session_id = ctx.obj.cdm.open() + log.info(f"CDM Session ID - {session_id.hex()}") + wrm_header = PSSH(track.pssh).get_wrm_headers(downgrade_to_v4=True)[0] # Downgrade to v4 is necessary for ATVP + challenge = ctx.obj.cdm.get_license_challenge(session_id, wrm_header) + #log.info(f"{wrm_header} --> {challenge}") + try: + ctx.obj.cdm.parse_license( + session_id, + base64.b64decode( + service.license( + challenge=challenge, + title=title, + track=track, + ).encode("ascii") + ).decode("ascii") + ) + except: + ctx.obj.cdm.parse_license( + session_id, + service.license( + challenge=challenge, + title=title, + track=track, + ) + ) + except requests.HTTPError as e: + log.debug(traceback.format_exc()) + raise log.exit(f" - HTTP Error {e.response.status_code}: {e.response.reason}") - ctx.obj.cdm.close(session_id) + content_keys = [ + (x.kid, x.key) for x in ctx.obj.cdm.get_keys(session_id, content_only=True) + ] if "common_privacy_cert" in dir(ctx.obj.cdm) else [ + (str(x.key_id).replace("-", ""), x.key.hex()) for x in ctx.obj.cdm.get_keys(session_id) + ] - if not content_keys: - raise log.exit(" - No content keys were returned by the CDM!") - log.info(f" + Obtained content keys from the CDM") - - for kid, key in content_keys: - if kid == "b770d5b4bb6b594daf985845aae9aa5f": - # Amazon HDCP test key - continue - log.info(f" + {kid}:{key}") - - # cache keys into all key vaults - for vault in ctx.obj.vaults.vaults: - log.info(f"Caching to {vault} vault") - cached = 0 - already_exists = 0 - for kid, key in content_keys: - result = ctx.obj.vaults.insert_key(vault, service_name.lower(), kid, key, title.id) - if result == InsertResult.FAILURE: - log.warning(f" - Failed, table {service_name.lower()} doesn't exist in the vault.") - elif result == InsertResult.SUCCESS: - cached += 1 - elif result == InsertResult.ALREADY_EXISTS: - already_exists += 1 - ctx.obj.vaults.commit(vault) - log.info(f" + Cached {cached}/{len(content_keys)} keys") - if already_exists: - log.info(f" + {already_exists}/{len(content_keys)} keys already existed in vault") - if cached + already_exists < len(content_keys): - log.warning(f" Failed to cache {len(content_keys) - cached - already_exists} keys") - # use matching content key for the tracks key id - track.key = next((key for kid, key in content_keys if kid == track.kid), None) - if track.key: - log.info(f" + KEY: {track.key} (From CDM)") - else: - raise log.exit(f" - No content key with the key ID \"{track.kid}\" was returned") - if keys: - continue - # TODO: Move decryption code to Track - if not config.decrypter: - raise log.exit(" - No decrypter specified") - if config.decrypter == "packager" and not (track.descriptor == Track.Descriptor.ISM): - platform = {"win32": "win", "darwin": "osx"}.get(sys.platform, sys.platform) - names = ["shaka-packager", "packager", f"packager-{platform}"] - executable = next((x for x in (shutil.which(x) for x in names) if x), None) - if not executable: - raise log.exit(" - Unable to find packager binary") - dec = os.path.splitext(track.locate())[0] + ".dec.mp4" - - os.makedirs(directories.temp, exist_ok=True) - try: - os.makedirs(directories.temp, exist_ok=True) - subprocess.run([ - executable, - "input={},stream={},output={}".format( - track.locate(), - track.__class__.__name__.lower().replace("track", ""), - dec - ), - "--enable_raw_key_decryption", "--keys", - ",".join([ - f"label=0:key_id={track.kid.lower()}:key={track.key.lower()}", - # Apple TV+ needs this as shaka pulls the incorrect KID, idk why - f"label=1:key_id=00000000000000000000000000000000:key={track.key.lower()}", - ]), - "--temp_dir", directories.temp - ], check=True) - except subprocess.CalledProcessError: - raise log.exit(" - Failed!") - - elif config.decrypter == "mp4decrypt" or (track.descriptor == Track.Descriptor.ISM): - executable = shutil.which("mp4decrypt") - if not executable: - raise log.exit(" - Unable to find mp4decrypt binary") - dec = os.path.splitext(track.locate())[0] + ".dec.mp4" - try: - subprocess.run([ - executable, - "--show-progress", - "--key", f"{track.kid.lower()}:{track.key.lower()}", - track.locate(), - dec, - ]) - except subprocess.CalledProcessError: - raise log.exit(" - Failed!") - else: - log.exit(f" - Unsupported decrypter: {config.decrypter}") - track.swap(dec) - log.info(" + Decrypted") + try: + ctx.obj.cdm.close(session_id) + except Exception as e: + raise log.exit(f" - Failed to close CDM session: {e}") - if keys: - continue + if not content_keys: + raise log.exit(" - No content keys were returned by the CDM!") + log.info(f" + Obtained content keys from the CDM") + + for kid, key in content_keys: + if kid == "b770d5b4bb6b594daf985845aae9aa5f": + # Amazon HDCP test key + continue + log.info(f" + {kid}:{key}") + + # cache keys into all key vaults + for vault in ctx.obj.vaults.vaults: + log.info(f"Caching to {vault} vault") + cached = 0 + already_exists = 0 + for kid, key in content_keys: + result = ctx.obj.vaults.insert_key(vault, service_name.lower(), kid, key, title.id) + if result == InsertResult.FAILURE: + log.warning(f" - Failed, table {service_name.lower()} doesn't exist in the vault.") + elif result == InsertResult.SUCCESS: + cached += 1 + elif result == InsertResult.ALREADY_EXISTS: + already_exists += 1 + ctx.obj.vaults.commit(vault) + log.info(f" + Cached {cached}/{len(content_keys)} keys") + if already_exists: + log.info(f" + {already_exists}/{len(content_keys)} keys already existed in vault") + if cached + already_exists < len(content_keys): + log.warning(f" Failed to cache {len(content_keys) - cached - already_exists} keys") + # use matching content key for the tracks key id + track.key = next((key for kid, key in content_keys if kid == track.kid), None) + if track.key: + log.info(f" + KEY: {track.key} (From CDM)") + else: + raise log.exit(f" - No content key with the key ID \"{track.kid}\" was returned") + if keys: + continue + # TODO: Move decryption code to Track + if not config.decrypter: + raise log.exit(" - No decrypter specified") + if config.decrypter == "packager": + platform = {"win32": "win", "darwin": "osx"}.get(sys.platform, sys.platform) + names = ["shaka-packager", "packager", f"packager-{platform}"] + executable = next((x for x in (shutil.which(x) for x in names) if x), None) + if not executable: + raise log.exit(" - Unable to find packager binary") + dec = os.path.splitext(track.locate())[0] + ".dec.mp4" + try: + os.makedirs(directories.temp, exist_ok=True) + subprocess.run([ + executable, + "input={},stream={},output={}".format( + track.locate(), + track.__class__.__name__.lower().replace("track", ""), + dec + ), + "--enable_raw_key_decryption", "--keys", + ",".join([ + f"label=0:key_id={track.kid.lower()}:key={track.key.lower()}", + # Apple TV+ needs this as shaka pulls the incorrect KID, idk why + f"label=1:key_id=00000000000000000000000000000000:key={track.key.lower()}", + ]), + "--temp_dir", directories.temp + ], check=True) + except subprocess.CalledProcessError: + raise log.exit(" - Failed!") + elif config.decrypter == "mp4decrypt": + executable = shutil.which("mp4decrypt") + if not executable: + raise log.exit(" - Unable to find mp4decrypt binary") + dec = os.path.splitext(track.locate())[0] + ".dec.mp4" + try: + subprocess.run([ + executable, + "--show-progress", + "--key", f"{track.kid.lower()}:{track.key.lower()}", + track.locate(), + dec, + ]) + except subprocess.CalledProcessError: + raise log.exit(" - Failed!") + else: + log.exit(f" - Unsupported decrypter: {config.decrypter}") + track.swap(dec) + log.info(" + Decrypted") - if track.needs_repack or (config.decrypter == "mp4decrypt" and isinstance(track, (VideoTrack, AudioTrack))): - log.info("Repackaging stream with FFmpeg (to fix malformed streams)") - track.repackage() - log.info(" + Repackaged") + if keys: + continue - if isinstance(track, VideoTrack) and track.needs_ccextractor and not no_subs: - ccextractor() - if skip_title: - for track in title.tracks: - track.delete() - continue - if keys: - continue - if not list(title.tracks) and not title.tracks.chapters: - continue - # mux all final tracks to a single mkv file - if no_mux: - if title.tracks.chapters: - final_file_path = directories.downloads - if title.type == Title.Types.TV: - final_file_path = os.path.join(final_file_path, title.parse_filename(folder=True)) - os.makedirs(final_file_path, exist_ok=True) - chapters_loc = filenames.chapters.format(filename=title.filename) - title.tracks.export_chapters(chapters_loc) - shutil.move(chapters_loc, os.path.join(final_file_path, os.path.basename(chapters_loc))) - for track in title.tracks: - media_info = MediaInfo.parse(track.locate()) - #log.debug(media_info) - final_file_path = directories.downloads - if title.type == Title.Types.TV: - final_file_path = os.path.join( - final_file_path, title.parse_filename(folder=True) - ) - os.makedirs(final_file_path, exist_ok=True) - filename = title.parse_filename(media_info=media_info) - if isinstance(track, (AudioTrack, TextTrack)): - filename += f".{track.language}" - extension = track.codec if isinstance(track, TextTrack) else os.path.splitext(track.locate())[1][1:] - if isinstance(track, AudioTrack) and extension == "mp4": - extension = "m4a" - track.move(os.path.join(final_file_path, f"{filename}.{track.id}.{extension}")) - else: - log.info("Muxing tracks into an MKV container") - muxed_location, returncode = title.tracks.mux(title.filename) - if returncode == 1: - log.warning(" - mkvmerge had at least one warning, will continue anyway...") - elif returncode >= 2: - raise log.exit(" - Failed to mux tracks into MKV file") - log.info(" + Muxed") - for track in title.tracks: - track.delete() - if title.tracks.chapters: - try: - os.unlink(filenames.chapters.format(filename=title.filename)) - except FileNotFoundError: - pass - media_info = MediaInfo.parse(muxed_location) - final_file_path = directories.downloads - if title.type == Title.Types.TV: - final_file_path = os.path.join( - final_file_path, title.parse_filename(media_info=media_info, folder=True) - ) - os.makedirs(final_file_path, exist_ok=True) - # rename muxed mkv file with new data from mediainfo data of it - if audio_only: - extension = "mka" - elif subs_only: - extension = "mks" - else: - extension = "mkv" - shutil.move( - muxed_location, - os.path.join(final_file_path, f"{title.parse_filename(media_info=media_info)}.{extension}") - ) - + if track.needs_repack or (config.decrypter == "mp4decrypt" and isinstance(track, (VideoTrack, AudioTrack))): + log.info("Repackaging stream with FFmpeg (to fix malformed streams)") + track.repackage() + log.info(" + Repackaged") - log.info("Processed all titles!") + if isinstance(track, VideoTrack) and track.needs_ccextractor and not no_subs: + ccextractor() + if skip_title: + for track in title.tracks: + track.delete() + continue + if keys: + continue + if not list(title.tracks) and not title.tracks.chapters: + continue + # mux all final tracks to a single mkv file + if no_mux: + if title.tracks.chapters: + final_file_path = directories.downloads + if title.type == Title.Types.TV: + final_file_path = os.path.join(final_file_path, title.parse_filename(folder=True)) + os.makedirs(final_file_path, exist_ok=True) + chapters_loc = filenames.chapters.format(filename=title.filename) + title.tracks.export_chapters(chapters_loc) + shutil.move(chapters_loc, os.path.join(final_file_path, os.path.basename(chapters_loc))) + for track in title.tracks: + media_info = MediaInfo.parse(track.locate()) + final_file_path = directories.downloads + if title.type == Title.Types.TV: + final_file_path = os.path.join( + final_file_path, title.parse_filename(folder=True) + ) + os.makedirs(final_file_path, exist_ok=True) + filename = title.parse_filename(media_info=media_info) + if isinstance(track, (AudioTrack, TextTrack)): + filename += f".{track.language}" + extension = track.codec if isinstance(track, TextTrack) else os.path.splitext(track.locate())[1][1:] + if isinstance(track, AudioTrack) and extension == "mp4": + extension = "m4a" + track.move(os.path.join(final_file_path, f"{filename}.{track.id}.{extension}")) + else: + log.info("Muxing tracks into an MKV container") + muxed_location, returncode = title.tracks.mux(title.filename) + if returncode == 1: + log.warning(" - mkvmerge had at least one warning, will continue anyway...") + elif returncode >= 2: + raise log.exit(" - Failed to mux tracks into MKV file") + log.info(" + Muxed") + for track in title.tracks: + track.delete() + if title.tracks.chapters: + try: + os.unlink(filenames.chapters.format(filename=title.filename)) + except FileNotFoundError: + pass + media_info = MediaInfo.parse(muxed_location) + final_file_path = directories.downloads + if title.type == Title.Types.TV: + final_file_path = os.path.join( + final_file_path, title.parse_filename(media_info=media_info, folder=True) + ) + os.makedirs(final_file_path, exist_ok=True) + # rename muxed mkv file with new data from mediainfo data of it + if audio_only: + extension = "mka" + elif subs_only: + extension = "mks" + else: + extension = "mkv" + shutil.move( + muxed_location, + os.path.join(final_file_path, f"{title.parse_filename(media_info=media_info)}.{extension}") + ) + + + log.info("Processed all titles!") def load_services(): - for service in services.__dict__.values(): - if callable(getattr(service, "cli", None)): - dl.add_command(service.cli) + for service in services.__dict__.values(): + if callable(getattr(service, "cli", None)): + dl.add_command(service.cli) load_services() diff --git a/vinetrimmer/commands/dl_new.py b/vinetrimmer/commands/dl_3.py similarity index 100% rename from vinetrimmer/commands/dl_new.py rename to vinetrimmer/commands/dl_3.py diff --git a/vinetrimmer/config/Services/amazon.yml b/vinetrimmer/config/Services/amazon.yml index d7f7390..8701be4 100644 --- a/vinetrimmer/config/Services/amazon.yml +++ b/vinetrimmer/config/Services/amazon.yml @@ -10,57 +10,25 @@ certificate: | 8Swf device: - - old: # !<< take note that this is done per-profile + new: # !<< take note that this is done per-profile domain: Device app_name: AIV app_version: '3.12.0' - device_model: 'SHIELD Android TV' + device_model: 'SHIELD Android TV' # gets ISM os_version: '28' device_type: A1KAXIG6VXSG8Y - device_serial: '13f5b56b4a17de5d136f0e4c28236109' # os.urandom().hex() - device_name: "Build/LMY47D Shield TV" + device_serial: '13f5b56b4a17de5d136f0e4c28236109' # `os.urandom(8).hex()` + device_name: "%FIRST_NAME%'s%DUPE_STRATEGY_1ST% Shield TV" software_version: '248' - - old2: - 'domain': 'DeviceLegacy' - 'device_type': A1KAXIG6VXSG8Y, - 'device_serial': '870f53d1b509594c2f8cd5e340a7d374' - 'app_name': 'com.amazon.avod.thirdpartyclient' - 'app_version': '296016847' - 'device_model': 'mdarcy/nvidia/SHIELD Android TV' - 'os_version': 'NVIDIA/mdarcy/mdarcy:11/RQ1A.210105.003/7094531_2971.7725:user/release-keys' - - old3: - domain: Device - app_name: com.amazon.amazonvideo.livingroom - app_version: '1.4' - device_model: PadFone - os_version: '6.2.5' - device_type: 'A2SNKIF736WF4T' - device_name: 'T008 Build/JSS15Q PadFone' # "%FIRST_NAME%'s%DUPE_STRATEGY_1ST% PadFone" - device_serial: 'c1ebbb433da4afdf' - - old4: - domain: Device - app_name: com.amazon.amazonvideo.livingroom - app_version: '1.4' - device_model: 'Hisense TV' - os_version: '3.9.5' - device_type: 'A3T3XXY42KZQNP' # A2B5DGIWVDH8J3, A3GTP8TAF8V3YG, AFTHA001 # https://developer.amazon.com/docs/fire-tv/identify-amazon-fire-tv-devices.html, https://github.com/giofrida/Hisense-Amazon-Enabler - device_name: "%FIRST_NAME%'s%DUPE_STRATEGY_1ST% Hisense" # KS964, Build/RP1A.201005.001 - device_serial: '8e3ddf49ee384247' - default: domain: Device app_name: com.amazon.amazonvideo.livingroom app_version: '1.1' - device_model: Hisense - os_version: '6.0.1' #6.10.19 - device_type: 'A3REWRVYBYPKUM' - device_name: '%FIRST_NAME%''s%DUPE_STRATEGY_1ST% Hisense' - device_serial: '3cc61028646759e273' - + device_model: PadFone + os_version: '6.0.1' + device_type: 'A2SNKIF736WF4T' + device_name: '%FIRST_NAME%''s%DUPE_STRATEGY_1ST% PadFone' + device_serial: 'a83a92c9b6cb4ca0' device_types: browser: 'AOAGZA014O5RE' # all browsers? all platforms? @@ -100,7 +68,6 @@ endpoints: codepair: '/auth/create/codepair' register: '/auth/register' token: '/auth/token' - #cookies: '/ap/exchangetoken/cookies' regions: us: diff --git a/vinetrimmer/config/Services/appletvplus.yml b/vinetrimmer/config/Services/appletvplus.yml index 3667e9d..cb34238 100644 --- a/vinetrimmer/config/Services/appletvplus.yml +++ b/vinetrimmer/config/Services/appletvplus.yml @@ -1,7 +1,24 @@ -user_agent: 'ATVE/6.2.0 Android/10 build/6A226 maker/Google model/Chromecast FW/QTS2.200918.0337115981' # AppleTV6,2/11.1 | ATVE/1.1 FireOS/6.2.6.8 build/4A93 maker/Amazon model/FireTVStick4K FW/NS6268/2315 +user_agent: 'ATVE/1.1 FireOS/6.2.6.8 build/4A93 maker/Amazon model/FireTVStick4K FW/NS6268/2315' # AppleTV6,2/11.1 | ATVE/1.1 FireOS/6.2.6.8 build/4A93 maker/Amazon model/FireTVStick4K FW/NS6268/2315 endpoints: title: 'https://tv.apple.com/api/uts/v3/{type}/{id}' tv_episodes: 'https://tv.apple.com/api/uts/v2/view/show/{id}/episodes' manifest: 'https://tv.apple.com/api/uts/v2/view/product/{id}/personalized' license: 'https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/fpsRequest' # 'https://play.itunes.apple.com/WebObjects/MZPlay.woa/web/video/subscription/license' + homecanvas: 'https://tv.apple.com/api/uts/v3/canvases/channels/tvs.sbd.4000' + +device: + # I have no idea what these values are or what they represent. + # These might not even be device related. + utsk: '6e3013c6d6fae3c2::::::e08f7cfb96228836' # 6e3013c6d6fae3c2::::::e08f7cfb96228836 (?), 6e3013c6d6fae3c2::::::235656c069bb0efb (web), 6e3013c6d6fae3c2::::::e4e626d9198feeb7 (chrome) + caller: 'web' # ?, vz, web + sf: '143441' # "storefront", country | 143441: US, 143444: GB | 143443: DE For other countrys -> https://gist.github.com/BrychanOdlum/2208578ba151d1d7c4edeeda15b4e9b1 + v: '46' # "version" | latest: 46, web: 82 + pfm: 'appletv' # "platform" | appletv, vz, web + mfr: 'Apple' # "manufacturer" | Apple, Amazon + locale: 'en-US' + l: 'en' + brandId: 'tvs.sbd.4000' # ctx_brand - tvs.sbd.4000 is subscription channel, renting channel is tvs.sbd.9001, mls sport channel is tvs.sbd.7000 + count: '100' + skip: '0' + svcId: 'tvs.vds.4105' # tvs.vds.4054 diff --git a/vinetrimmer/config/Services/appletvplus1.yml b/vinetrimmer/config/Services/appletvplus1.yml deleted file mode 100644 index 8ea3d4a..0000000 --- a/vinetrimmer/config/Services/appletvplus1.yml +++ /dev/null @@ -1,24 +0,0 @@ -user_agent: 'ATVE/1.1 FireOS/6.2.6.8 build/4A93 maker/Amazon model/FireTVStick4K FW/NS6268/2315' # AppleTV6,2/11.1 | ATVE/1.1 FireOS/6.2.6.8 build/4A93 maker/Amazon model/FireTVStick4K FW/NS6268/2315 - -endpoints: - title: 'https://tv.apple.com/api/uts/v3/{type}/{id}' - tv_episodes: 'https://tv.apple.com/api/uts/v2/view/show/{id}/episodes' - manifest: 'https://tv.apple.com/api/uts/v2/view/product/{id}/personalized' - license: 'https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/fpsRequest' # 'https://play.itunes.apple.com/WebObjects/MZPlay.woa/web/video/subscription/license' - -device: - # I have no idea what these values are or what they represent. - # These might not even be device related. - utsk: '6e3013c6d6fae3c2::::::e08f7cfb96228836' # 6e3013c6d6fae3c2::::::e08f7cfb96228836 6e3013c6d6fae3c2::::::e08f7cfb96228836 (?), 6e3013c6d6fae3c2::::::235656c069bb0efb (web) - caller: 'web' # ?, vz, web - sf: '143441' # "storefront", country | 143441: US, 143444: GB | 143443: DE For other countrys ->https://gist.github.com/BrychanOdlum/2208578ba151d1d7c4edeeda15b4e9b1 - v: '46' # "version" | latest: 56 - pfm: 'appletv' # "platform" | appletv, vz, web - mfr: 'Apple' # "manufacturer" | Apple, Amazon - locale: 'en-US' - l: 'en' - brandId: 'tvs.sbd.4000' # ctx_brand/brandId - count: '100' - skip: '0' - svcId: 'tvs.vds.4105' - a: '1783518684' diff --git a/vinetrimmer/config/Services/max.yml b/vinetrimmer/config/Services/max.yml index 9bc052b..32fbf1b 100644 --- a/vinetrimmer/config/Services/max.yml +++ b/vinetrimmer/config/Services/max.yml @@ -3,6 +3,3 @@ endpoints: moviePages: 'https://default.any-any.prd.api.max.com/content/videos/%s/activeVideoForShow?&include=edit' playbackInfo: 'https://default.any-any.prd.api.max.com/any/playback/v1/playbackInfo' showPages: 'https://default.any-any.prd.api.max.com/cms/collections/generic-show-page-rail-episodes-tabbed-content?include=default&pf[show.id]=%s&%s' -account: - email: 'marccin1996@gmail.com' - pass: 'MarcinPawlak1996' \ No newline at end of file diff --git a/vinetrimmer/config/Services/peacock.yml b/vinetrimmer/config/Services/peacock.yml deleted file mode 100644 index 0b9a880..0000000 --- a/vinetrimmer/config/Services/peacock.yml +++ /dev/null @@ -1,27 +0,0 @@ -endpoints: - stream_tv: 'https://www.peacocktv.com/stream-tv/{title_id}' - config: 'https://config.clients.peacocktv.com/{territory}/{provider}/{proposition}/{device}/PROD/{version}/config.json' - login: 'https://rango.id.peacocktv.com/signin/service/international' - personas: 'https://persona.id.peacocktv.com/persona-store/personas' - tokens: 'https://ovp.peacocktv.com/auth/tokens' - me: 'https://ovp.peacocktv.com/auth/users/me' - node: 'https://atom.peacocktv.com/adapter-calypso/v3/query/node' - vod: 'https://ovp.peacocktv.com/video/playouts/vod' - -client: - config_version: '1.0.8' - territory: 'US' - provider: 'NBCU' - proposition: 'NBCUOTT' - platform: 'ANDROID' # PC, ANDROID - device: 'TABLET' # COMPUTER, TABLET - id: 'Jcvf1y0whKOI29vRXcJy' - drm_device_id: 'UNKNOWN' - client_sdk: 'NBCU-WEB-v4' # NBCU-ANDROID-v3 NBCU-ANDRTV-v4 - auth_scheme: 'MESSO' - auth_issuer: 'NOWTV' - -security: - signature_hmac_key_v4: 'FvT9VtwvhtSZvqnExMsvDDTEvBqR3HdsMcBFtWYV' - signature_hmac_key_v6: 'izU6EJqqu6DOhOWSk5X4p9dod3fNqH7vzKtYDK8d' - signature_format: 'SkyOTT client="{client}",signature="{signature}",timestamp="{timestamp}",version="1.0"' diff --git a/vinetrimmer/config/vinetrimmer.yml b/vinetrimmer/config/vinetrimmer.yml index 62cefda..6a8beb6 100644 --- a/vinetrimmer/config/vinetrimmer.yml +++ b/vinetrimmer/config/vinetrimmer.yml @@ -15,7 +15,7 @@ aria2c: cdm: - default: 'hisense_smarttv_he55a7000euwts_sl3000' + default: 'generic_8159_l3' cdm_api: [] diff --git a/vinetrimmer/key_store.db b/vinetrimmer/key_store.db index b836e33..c232116 100644 Binary files a/vinetrimmer/key_store.db and b/vinetrimmer/key_store.db differ diff --git a/vinetrimmer/objects/tracks.py b/vinetrimmer/objects/tracks.py index 41a58e2..30b7e36 100644 --- a/vinetrimmer/objects/tracks.py +++ b/vinetrimmer/objects/tracks.py @@ -20,11 +20,11 @@ from langcodes import Language from requests import Session from vinetrimmer import config from vinetrimmer.constants import LANGUAGE_MUX_MAP, TERRITORY_MAP -from vinetrimmer.utils import get_boxes, get_closest_match, is_close_match, try_get +from vinetrimmer.utils import Cdm, get_boxes, get_closest_match, is_close_match, try_get from vinetrimmer.utils.collections import as_list -from vinetrimmer.utils.io import aria2c, download_range, saldl, m3u8dl +from vinetrimmer.utils.io import aria2c, download_range, saldl from vinetrimmer.utils.subprocess import ffprobe -#from vinetrimmer.utils.widevine.protos.widevine_pb2 import WidevineCencHeader +from vinetrimmer.utils.widevine.protos.widevine_pb2 import WidevineCencHeader from vinetrimmer.utils.xml import load_xml from vinetrimmer.vendor.pymp4.parser import Box, MP4 @@ -63,7 +63,6 @@ class Track: URL = 1 # Direct URL, nothing fancy M3U = 2 # https://en.wikipedia.org/wiki/M3U (and M3U8) MPD = 3 # https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP - ISM = 4 # https://bitmovin.com/blog/microsoft-smooth-streaming-mss/ def __init__(self, id_, source, url, codec, language=None, descriptor=Descriptor.URL, needs_proxy=False, needs_repack=False, encrypted=False, pssh=None, note=None, kid=None, key=None, extra=None): @@ -403,6 +402,7 @@ class Track: segment.uri ) self.url = segments + if self.source == "CORE": asyncio.run(saldl( self.url, @@ -410,19 +410,21 @@ class Track: headers, proxy if self.needs_proxy else None )) - elif self.descriptor == self.Descriptor.ISM: - asyncio.run(m3u8dl( - self.url, - save_path, - self - )) else: - asyncio.run(aria2c( - self.url, - save_path, - headers, - proxy if self.needs_proxy else None - )) + try: + asyncio.run(aria2c( + self.url, + save_path, + headers, + proxy if self.needs_proxy else None + )) + except: + asyncio.run(aria2c( + self.url, + save_path, + headers, + proxy if self.needs_proxy else None + )) if os.stat(save_path).st_size <= 3: # Empty UTF-8 BOM == 3 bytes raise IOError( @@ -561,7 +563,7 @@ class VideoTrack(Track): url="", # doesn't need to be downloaded codec="srt", language=language, - is_original_lang=original, # TODO: Figure out if this is the original title language + #is_original_lang=original, # TODO: Figure out if this is the original title language cc=True ) cc_track._location = out_path diff --git a/vinetrimmer/parsers/ISM/[MS-SSTR].pdf b/vinetrimmer/parsers/ISM/[MS-SSTR].pdf new file mode 100644 index 0000000..9929325 Binary files /dev/null and b/vinetrimmer/parsers/ISM/[MS-SSTR].pdf differ diff --git a/vinetrimmer/parsers/ISM/ism.py b/vinetrimmer/parsers/ISM/ism.py new file mode 100644 index 0000000..5b60367 --- /dev/null +++ b/vinetrimmer/parsers/ISM/ism.py @@ -0,0 +1,132 @@ +import argparse +import requests +import xmltodict +import base64 +import uuid + +WV_SYSTEM_ID = [237, 239, 139, 169, 121, 214, 74, 206, 163, 200, 39, 220, 213, 29, 33, 237] + +def parse_manifest_ism(manifest_url): + r = requests.get(manifest_url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' + 'AppleWebKit/537.36 (KHTML, like Gecko) ' + 'Chrome/72.0.3626.121 Safari/537.36'}) + + if r.status_code != 200: + raise Exception(r.text) + + # Write to file + #with open("manifest", "w") as file: + # file.write(r.text) + + ism = xmltodict.parse(r.text) + + pssh = ism['SmoothStreamingMedia']['Protection']['ProtectionHeader']['#text'] + + pr_pssh_dec = base64.b64decode(pssh).decode('utf16') + pr_pssh_dec = pr_pssh_dec[pr_pssh_dec.index('<'):] + pr_pssh_xml = xmltodict.parse(pr_pssh_dec) + kid_hex = base64.b64decode(pr_pssh_xml['WRMHEADER']['DATA']['KID']).hex() + + kid = uuid.UUID(kid_hex).bytes_le + + init_data = bytearray(b'\x12\x10') + init_data.extend(kid) + init_data.extend(b'H\xe3\xdc\x95\x9b\x06') + + pssh = bytearray([0, 0, 0]) + pssh.append(32 + len(init_data)) + pssh[4:] = bytearray(b'pssh') + pssh[8:] = [0, 0, 0, 0] + pssh[13:] = WV_SYSTEM_ID + pssh[29:] = [0, 0, 0, 0] + pssh[31] = len(init_data) + pssh[32:] = init_data + + print('\nPSSH (WV): ', base64.b64encode(pssh)) + print('\nKID: {}'.format(kid.hex())) + + stream_indices = ism['SmoothStreamingMedia']['StreamIndex'] + + # List to store information for each stream + stream_info_list = [] + + # Iterate over each StreamIndex (as it might be a list) + for stream_info in stream_indices if isinstance(stream_indices, list) else [stream_indices]: + type_info = stream_info['@Type'] + + if type_info in {'video', 'audio'}: + # Handle the case where there can be multiple QualityLevel elements + quality_levels = stream_info.get('QualityLevel', []) + + if not isinstance(quality_levels, list): + quality_levels = [quality_levels] + + for quality_level in quality_levels: + codec = quality_level.get('@FourCC', 'N/A') + bitrate = quality_level.get('@Bitrate', 'N/A') + + # Additional attributes for video streams + if type_info == 'video': + max_width = quality_level.get('@MaxWidth', 'N/A') + max_height = quality_level.get('@MaxHeight', 'N/A') + resolution = f"{max_width}x{max_height}" + else: + resolution = 'N/A' + + # Additional attributes for audio streams + language = stream_info.get('@Language', 'N/A') + track_id = stream_info.get('@AudioTrackId', 'N/A') if type_info == 'audio' else None + + stream_info_list.append({ + 'type': type_info, + 'codec': codec, + 'bitrate': bitrate, + 'resolution': resolution, + 'language': language, + 'track_id': track_id + }) + + # PSSH encoding logic in ism (Below generates WV PSSH) + array_of_bytes = bytearray(b'\x00\x00\x002pssh\x00\x00\x00\x00') + array_of_bytes.extend(bytes.fromhex("edef8ba979d64acea3c827dcd51d21ed")) + array_of_bytes.extend(b'\x00\x00\x00\x12\x12\x10') + array_of_bytes.extend(bytes.fromhex(str(kid.hex()).replace("-", ""))) + + encoded_string = base64.b64encode(bytes.fromhex(array_of_bytes.hex())).decode("utf-8") + + return stream_info_list, encoded_string + + +def main(): + # Create an ArgumentParser object and add the 'urls' argument + parser = argparse.ArgumentParser(description='Script for parsing Smooth Streaming manifest URLs.') + parser.add_argument('urls', + help='The URLs to parse. You may need to wrap the URLs in double quotes if you have issues.', + nargs='+') + + # Parse the arguments + args = parser.parse_args() + + # Iterate over the provided URLs + for manifest_link in args.urls: + stream_info_list, encoded_string = parse_manifest_ism(manifest_link) + + # Print information for each stream + for stream_info in stream_info_list: + type_info = stream_info['type'] + codec = stream_info['codec'] + bitrate = stream_info['bitrate'] + resolution = stream_info['resolution'] + + if type_info == 'video': + print(f'[INFO] VIDEO - Codec: {codec}, Resolution: {resolution}, Bitrate: {bitrate}') + elif type_info == 'audio': + language = stream_info['language'] + track_id = stream_info['track_id'] + print(f'[INFO] AUDIO - Codec: {codec}, Bitrate: {bitrate}, Language: {language}, Track ID: {track_id}') + + # Print PSSH information + print('\n[INFO] PSSH:', encoded_string) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/vinetrimmer/parsers/ISM/ism_incorrect.py b/vinetrimmer/parsers/ISM/ism_incorrect.py new file mode 100644 index 0000000..b9749a9 --- /dev/null +++ b/vinetrimmer/parsers/ISM/ism_incorrect.py @@ -0,0 +1,95 @@ +import xml.etree.ElementTree as ET +import subprocess +import argparse +import os + +# Logger configuration +# logging.basicConfig(level=logging.DEBUG) + +# Get the URL of the ISM manifest file as a command line argument +parser = argparse.ArgumentParser(description='Download a PlayReady protected video.') +parser.add_argument('url', metavar='URL', type=str, help='URL of the ISM manifest file') +args = parser.parse_args() + +video_name = os.path.basename(args.url) +subprocess.run(['aria2c', args.url, '-o', video_name, '--out', video_name, '--allow-overwrite=true']) + +# Check if the .ism file is available +manifest_file = 'manifest' +if not os.path.isfile(manifest_file): + # Generate the .ism file with mp4split + subprocess.run(['mp4split', video_name, '--ism']) + +# Parse the manifest file with ElementTree +tree = ET.parse(manifest_file) +root = tree.getroot() + +# Define function to sort resolutions by file size +def sort_resolutions(resolution): + for child in root: + if child.tag == 'StreamIndex': + if child.attrib['Type'] == 'video': + for fragment in child: + if (fragment.get('MaxWidth', '0') + 'x' + fragment.get('MaxHeight', '0')) == resolution: + return int(fragment.get('Size', 0)) + return 0 + +# Show the available resolutions for the video sorted by file size +video_resolutions = [] +for child in root: + if child.tag == 'StreamIndex': + if child.attrib['Type'] == 'video': + for fragment in child: + resolution = fragment.get('MaxWidth', '0') + 'x' + fragment.get('MaxHeight', '0') + if resolution not in video_resolutions and resolution != '0x0': + video_resolutions.append(resolution) + +format_resolutions = [] +for i, resolution in enumerate(sorted(video_resolutions, key=sort_resolutions, reverse=True)): + is_hdr = False + codec = '' + bitrate = '' + for child in root: + if child.tag == 'StreamIndex': + if child.attrib['Type'] == 'video': + for fragment in child: + if (fragment.get('MaxWidth', '0') + 'x' + fragment.get('MaxHeight', '0')) == resolution: + codec = fragment.get('FourCC', '') + bitrate = fragment.get('Bitrate', '') + if codec in ['hev1']: + es_hdr = True + resolution_string = str(i+1) + '. ' + resolution + if is_hdr: + resolution_string += ' - HDR: true' + else: + resolution_string += ' - HDR: false' + if codec != '': + resolution_string += ' - Codec: ' + codec + if bitrate != '': + resolution_string += ' - Bitrate: ' + bitrate + ' kbps' + format_resolutions.append(resolution_string) + +print('Available resolutions for the video:') +for resolution in format_resolutions: + print(resolution) + +# Get information about audio channels +audio_channels = [] +for child in root: + if child.tag == 'StreamIndex': + if child.attrib['Type'] == 'audio': + lang_list = [] + for fragment in child: + codec = fragment.get('FourCC', '') + bitrate = fragment.get('Bitrate', '') + lang = fragment.get('Language', '') + if codec not in audio_channels and bitrate != '': + audio_channels.append(codec) + bitrate_kbps = int(bitrate) // 1000 + for l in lang.split(','): + lang_list.append(l.strip()) + audio_channel_string = str(len(audio_channels)) + '. Codec: ' + codec + ' - Bitrate: ' + str(bitrate_kbps) + ' kbps' + print(audio_channel_string) + +# Delete the .ism file +os.remove(manifest_file) \ No newline at end of file diff --git a/vinetrimmer/parsers/ISM/remove_chunk_data.py b/vinetrimmer/parsers/ISM/remove_chunk_data.py new file mode 100644 index 0000000..84378bd --- /dev/null +++ b/vinetrimmer/parsers/ISM/remove_chunk_data.py @@ -0,0 +1,10 @@ +with open ("manifest", "r") as file: + x = file.readlines() + +newLines = [] +for line in x: + if ">> VBR +http://a279avoddashs3ww-a.akamaihd.net/3$0CiQIAhILCgknJUM9XTtqayUgJTABUgOAwAJ6A4C4F4IBAQGIAQUYAQ/ondemand/iad_2/4f96/58c2/5203/4340-8f3c-3ef982928185/c34de7c6-9488-4a84-9d14-0ec03130a1a2_corrected.mpd?encoding=segmentBase +ca448355ec474c5a9faa0c3048bb04ac:5f6aee678e33e4b9da9398d2c9e5424e +8f6fd20e45d3499aaae614d274ca12f5:4c48e93411330b23081fbbdffd407c45 + +>> CBR +http://avodsls3ww-s.akamaihd.net/d/2$u0KjZhxoqD1sCHceECSyo5zvYOY/ondemand/iad_2/6823/1854/fa7d/4516-8f57-472638c2bc33/16d6f5fc-c8fa-4291-bf08-9d8ccb8e78d8.ism/manifest?encoding=segmentBase +a6db02c76088a449bd6124fb85087061:3198d1d4212cbe8b35eff1bf8092ce11 +32cc6b20b5094ef0a0b1e0222b9ab749:e8fa326212611639b26e41d8b5c5bc25 + +• 4K CBR+VBR (HDR) +>>> VBR +http://a63avoddashs3ww-a.akamaihd.net/3$0CiQIAhILCgknJUM9XTtqayUgJTABUgOAwAJ6A4C4F4IBAQGIAQUYAQ/ondemand/iad_2/fb84/d47e/232b/4a44-bf88-2166d495df17/acd41e6d-fcc5-4136-9206-ced85bb474f9_corrected.mpd?encoding=segmentBase +196d417b4cce4aaa82510ce1b876581f:264208e5699681c265f86911442da189 +18e1d971a222437e956ea0ac34ee431e:137ebd74fb3bb880b1dba6df4e129585 + +>> CBR +http://a192avoddashs3ww-a.akamaihd.net/3$0CiQIAhILCgknJUM9XTtqayUgJTABUgOAwAJ6A4C4F4IBAQGIAQUYAQ/ondemand/iad_2/143f/e3ac/435f/4a2a-b328-1e3ec4fe0730/9d856266-f2b6-4dd7-b8df-ea885cf17a1d_corrected.mpd?encoding=segmentBase +cf22c31519c74cc184712b1736ab2d34:2afae3ac1562fce5c7b49fbdda7ebe63 +32cc6b20b5094ef0a0b1e0222b9ab749:e8fa326212611639b26e41d8b5c5bc25 + +• 1080p-CBR +https://a207avoddashs3ww-a.akamaihd.net/3$0CicIAhILCgklaj0lO11DaycgJTABUgaAwAKB8AN6A4C4F4IBAQGIAQQYAQ/ondemand/iad_2/710c/1829/2a53/486b-86da-c1baf570530e/338f68c0-0a57-42b1-9f26-83699fa5ccb0_corrected.mpd?encoding=segmentBase +1949c80fdfda4597bf0b032770a403f2:d213dccd3645b5847422d3e8d0223620 +9e7effb726344af0b45a3926d0a26e31:64e50593a3f267e6a6efde76f53ca7e0 + +• 1080p-VBR +https://a68avoddashs3ww-a.akamaihd.net/3$0CicIAhILCgklaj0lO11DaycgJTABUgaAwAKB8AN6A4C4F4IBAQGIAQQYAQ/ondemand/iad_2/38b5/b1f3/fe86/45e0-a4ce-f3299dbf53a8/6e74decd-ed2e-4bc9-b207-4aaa448685fc_corrected.mpd?encoding=segmentBase +dc1e823712344d5abf71a5343fd0df20:0bef8bb5e47c9a28dbd25b97182d0584 +32cc6b20b5094ef0a0b1e0222b9ab749:e8fa326212611639b26e41d8b5c5bc25 + +• 1080p-H265 +https://a256avoddashs3ww-a.akamaihd.net/3$0CicIAhILCgklaj0lO11DaycgJTABUgaAwAKB8AN6A4C4F4IBAQGIAQQYAQ/ondemand/iad_2/4761/b20f/a8b0/48fa-a6a0-f8b8795df24a/630d4038-f68f-4f82-af4e-46a03764f7c1_corrected.mpd?encoding=segmentBase +32cc6b20b5094ef0a0b1e0222b9ab749:e8fa326212611639b26e41d8b5c5bc25 + + +Tommy Little: Self Diagnosed Genius ISM +http://avodsls3ww-s.akamaihd.net/ondemand/iad_2/d8c6/0083/8321/4d2a-b780-54f6cb1ec9e0/e26d8208-5a97-4d1b-b49b-0a198e763c9c.ism/manifest \ No newline at end of file diff --git a/vinetrimmer/parsers/__init__.py b/vinetrimmer/parsers/__init__.py index ffb85bf..c503ab8 100644 --- a/vinetrimmer/parsers/__init__.py +++ b/vinetrimmer/parsers/__init__.py @@ -1,3 +1,3 @@ -from vinetrimmer.parsers import m3u8, mpd, ism +from vinetrimmer.parsers import m3u8, mpd -__all__ = ["m3u8", "mpd", "ism"] +__all__ = ["m3u8", "mpd"] diff --git a/vinetrimmer/parsers/ism.py b/vinetrimmer/parsers/ism.py index 4f9690c..c7c7d10 100644 --- a/vinetrimmer/parsers/ism.py +++ b/vinetrimmer/parsers/ism.py @@ -16,13 +16,12 @@ from langcodes.tag_parser import LanguageTagError from vinetrimmer import config from vinetrimmer.objects import AudioTrack, TextTrack, Track, Tracks, VideoTrack +from vinetrimmer.utils import Cdm from vinetrimmer.utils.io import aria2c +from vinetrimmer.utils.xml import load_xml from vinetrimmer.vendor.pymp4.parser import Box -# A stream from ISM is always in fragments -# Example fragment URL -# https://test.playready.microsoft.com/media/profficialsite/tearsofsteel_4k.ism.smoothstreaming/QualityLevels(128003)/Fragments(aac_UND_2_128=0) -# based on https://github.com/SASUKE-DUCK/pywks/blob/dba8a83a0722221bd8d3e53d624b91050b46cfde/cdm/wks.py#L722 + def parse(*, url=None, data=None, source, session=None, downloader=None): """ Convert an Smooth Streaming ISM (IIS Smooth Streaming Manifest) document to a Tracks object @@ -54,6 +53,7 @@ def parse(*, url=None, data=None, source, session=None, downloader=None): session = requests.Session(headers={"X-Example": "foo"}) tracks = Tracks.from_ism(url=url, data=session.get(url).text, source="MICROSOFT") """ + tracks = [] if not data: if not url: raise ValueError("Neither a URL nor a document was provided to Tracks.from_ism") @@ -74,169 +74,6 @@ def parse(*, url=None, data=None, source, session=None, downloader=None): else: raise ValueError(f"Unsupported downloader: {downloader}") - ism = xmltodict.parse(data) - if not ism["SmoothStreamingMedia"]: + root = load_xml(data) + if root.tag != "SmoothStreamingMedia": raise ValueError("Non-ISM document provided to Tracks.from_ism") - - encrypted = \ - ( True if ism['SmoothStreamingMedia']['Protection']['ProtectionHeader']['@SystemID'] - and - ism['SmoothStreamingMedia']['Protection']['ProtectionHeader']['@SystemID'].replace("-", "").upper() - in ["9A04F07998404286AB92E65BE0885F95", 'EDEF8BA979D64ACEA3C827DCD51D21ED'] - else False - ) - pssh = ism['SmoothStreamingMedia']['Protection']['ProtectionHeader']['#text'] - pr_pssh_dec = base64.b64decode(pssh).decode('utf16') - pr_pssh_dec = pr_pssh_dec[pr_pssh_dec.index('<'):] - pr_pssh_xml = xmltodict.parse(pr_pssh_dec) - kid_hex = base64.b64decode(pr_pssh_xml['WRMHEADER']['DATA']['KID']).hex() - kid = uuid.UUID(kid_hex).bytes_le - - stream_indices = ism['SmoothStreamingMedia']['StreamIndex'] - - assert int(ism['SmoothStreamingMedia'].get('@Duration')) - assert int(ism['SmoothStreamingMedia'].get('@TimeScale')) - - # Seconds - duration = int(ism['SmoothStreamingMedia'].get('@Duration')) / int(ism['SmoothStreamingMedia'].get('@TimeScale')) - - # List to store information for each stream - tracks = [] - - # Iterate over each StreamIndex (as it might be a list) - for stream_info in stream_indices if isinstance(stream_indices, list) else [stream_indices]: - - # For some reason Chunks will be roughly equal to int of half of duration in seconds - #chunks_calc = int(duration / 2) - #chunks = stream_info['@Chunks'] - #if chunks != chunks_calc: - # log.warn(f"{chunks} number of fragments is not equal to calculated number of fragments {chunks_calc}") - - - type_info = stream_info['@Type'] - - - # Handle the case where there can be multiple QualityLevel elements - quality_levels = stream_info.get('QualityLevel', []) - if not isinstance(quality_levels, list): - quality_levels = [quality_levels] - - for quality_level in quality_levels: - fourCC = quality_level.get('@FourCC', 'N/A') - bitrate = int ( quality_level.get('@Bitrate', 'N/A') ) # Bytes per second - - global max_width - global max_height - # Additional attributes for video streams - if type_info == 'video': - max_width = quality_level.get('@MaxWidth', 'N/A') - max_height = quality_level.get('@MaxHeight', 'N/A') - resolution = f"{max_width}x{max_height}" - else: - resolution = 'N/A' - - privateData = quality_level.get('@CodecPrivateData', 'N/A').strip() - if privateData == "N/A" or privateData == "": - privateData = None - #privateData = GenCodecPrivateDataForAAC() - - if fourCC in ["H264", "X264", "DAVC", "AVC1"]: - try: - result = re.compile(r"00000001\d7([0-9a-fA-F]{6})").match(privateData)[1] - codec = f"avc1.{result}" - except: - codec = "avc1.4D401E" - elif fourCC[:3] == "AAC": # ["AAC", "AACL", "AACH", "AACP"] - mpProfile = 2 - if fourCC == "AACH": - mpProfile = 5 # High Efficiency AAC Profile - elif privateData != "N/A" or privateData != "": - mpProfile = (int(privateData[:2], 16) & 0xF8) >> 3 - if mpProfile == 0: mpProfile = 2 # Return default audio codec - codec = f"mp4a.40.{mpProfile}" - else: - codec = fourCC - - # Additional attributes for audio streams - lang = stream_info.get('@Language', 'N/A').strip() - - try: - lang = Language.get(lang.split("-")[0]) - except: - lang = Language.get("und") - - audio_id = stream_info.get('@AudioTrackId', 'N/A') - - track_id = "{codec}-{lang}-{bitrate}-{extra}".format( - codec=codec, - lang=lang, - bitrate=bitrate or 0, # subs may not state bandwidth - extra=(audio_id or "") + (quality_level.get("@Index") or "") + privateData, - ) - track_id = md5(track_id.encode()).hexdigest() - - url_template: str = stream_info.get("@Url").replace("{bitrate}", f"{bitrate}").replace("{start time}", "0") - init_url = url.replace("manifest", url_template) - #init = (session or requests).get(init_url).text - # if pssh: - # pssh = base64.b64decode(pssh) - # # noinspection PyBroadException - # try: - # pssh = Box.parse(pssh) - - # except Exception: - # pssh = Box.parse(Box.build(dict( - # type=b"pssh", - # version=0, # can only assume version & flag are 0 - # flags=0, - # system_ID=Cdm.uuid, - # init_data=pssh - # ))) - if type_info == 'video': - tracks.append(VideoTrack( - id_=track_id, - source=source, - url=url, - # metadata - codec=(codec or "").split(".")[0], - language=lang, - bitrate=bitrate, - width=max_width, - height=max_height, - fps=None, - hdr10=codec and codec[0:4] in ("hvc1", "hev1"), # and codec[5] == 2, # hevc.2XXXXX or hvc1.2XXXXX Needs the hevc full codec script translated from Nm3u8 - hlg=False, - dv=codec and codec[0:4] in ("dvhe", "dvh1"), - # switches/options - descriptor=Track.Descriptor.ISM, - # decryption - needs_repack=True, # Necessary - encrypted=encrypted, - pssh=pssh, - kid=kid, - # extra - extra=(list(quality_level), list(stream_info),) # Either set size as a attribute of VideoTrack or append to extra here. - )) - elif type_info == 'audio': - atmos = ( str( quality_level.get('@HasAtmos', 'N/A') ).lower() == "true" ) or ( "ATM" in stream_info.get('@Name', 'N/A') ) - tracks.append(AudioTrack( - id_=track_id, - source=source, - url=url, - # metadata - codec=(codec or "").split(".")[0], - language=lang, - bitrate=bitrate, - channels=quality_level.get('@Channels', 'N/A'), - atmos=atmos, - # switches/options - descriptor=Track.Descriptor.ISM, - # decryption - needs_repack=False, # Necessary - encrypted=encrypted, - pssh=pssh, - kid=kid, - # extra - extra=(dict(quality_level), dict(stream_info),) - )) - return tracks diff --git a/vinetrimmer/parsers/m3u8.py b/vinetrimmer/parsers/m3u8.py index 07cf8b6..46a9572 100644 --- a/vinetrimmer/parsers/m3u8.py +++ b/vinetrimmer/parsers/m3u8.py @@ -3,7 +3,7 @@ import re from hashlib import md5 from vinetrimmer.objects import AudioTrack, TextTrack, Track, Tracks, VideoTrack -#from vinetrimmer.utils import Cdm +from vinetrimmer.utils import Cdm from vinetrimmer.vendor.pymp4.parser import Box @@ -68,7 +68,7 @@ def parse(master, source=None): fps=x.stream_info.frame_rate, hdr10=(x.stream_info.codecs.split(".")[0] not in ("dvhe", "dvh1") and (x.stream_info.video_range or "SDR").strip('"') != "SDR"), - hlg=False, # TODO: Can we get this from the manifest.xml? + hlg=False, # TODO: Can we get this from the manifest? dv=x.stream_info.codecs.split(".")[0] in ("dvhe", "dvh1"), # switches/options descriptor=Track.Descriptor.M3U, diff --git a/vinetrimmer/parsers/mpd.py b/vinetrimmer/parsers/mpd.py index f00e27e..a7628fc 100644 --- a/vinetrimmer/parsers/mpd.py +++ b/vinetrimmer/parsers/mpd.py @@ -16,8 +16,10 @@ from langcodes.tag_parser import LanguageTagError from vinetrimmer import config from vinetrimmer.objects import AudioTrack, TextTrack, Track, Tracks, VideoTrack +from vinetrimmer.utils import Cdm from vinetrimmer.utils.io import aria2c from vinetrimmer.utils.xml import load_xml +from vinetrimmer.vendor.pymp4.parser import Box def parse(*, url=None, data=None, source, session=None, downloader=None): @@ -44,19 +46,17 @@ def parse(*, url=None, data=None, source, session=None, downloader=None): tracks = Tracks.from_mpd( url, session=session, - source="DOLBY" + source="DOLBY", ) url = "http://media.developer.dolby.com/DolbyVision_Atmos/profile8.1_DASH/p8.1.mpd" session = requests.Session(headers={"X-Example": "foo"}) tracks = Tracks.from_mpd(url=url, data=session.get(url).text, source="DOLBY") """ - tracks = [] if not data: if not url: raise ValueError("Neither a URL nor a document was provided to Tracks.from_mpd") - global base_url base_url = url.rsplit('/', 1)[0] + '/' if downloader is None: data = (session or requests).get(url).text @@ -91,7 +91,7 @@ def parse(*, url=None, data=None, source, session=None, downloader=None): if any(x.get("schemeIdUri") == "http://dashif.org/guidelines/trickmode" for x in adaptation_set.findall("EssentialProperty") + adaptation_set.findall("SupplementalProperty")): - # Skip trick mode streams (used for fast-forward/rewind) + # Skip trick mode streams (used for fast forward/rewind) continue for rep in adaptation_set.findall("Representation"): @@ -194,13 +194,13 @@ def parse(*, url=None, data=None, source, session=None, downloader=None): track_url = [] - def replace_fields(link, **kwargs): + def replace_fields(url, **kwargs): for field, value in kwargs.items(): - link = link.replace(f"${field}$", str(value)) - m = re.search(fr"\${re.escape(field)}%([a-z0-9]+)\$", link, flags=re.I) + url = url.replace(f"${field}$", str(value)) + m = re.search(fr"\${re.escape(field)}%([a-z0-9]+)\$", url, flags=re.I) if m: - link = link.replace(m.group(), f"{value:{m.group(1)}}") - return link + url = url.replace(m.group(), f"{value:{m.group(1)}}") + return url initialization = segment_template.get("initialization") if initialization: @@ -335,7 +335,7 @@ def parse(*, url=None, data=None, source, session=None, downloader=None): sub_path_url = segment_template.get('media') try: - path = re.search(r"(t\/.+?\/)t", sub_path_url).group(1) + path = re.search(r'(t\/.+?\/)t', sub_path_url).group(1) except AttributeError: path = 't/sub/' diff --git a/vinetrimmer/services/__init__.py b/vinetrimmer/services/__init__.py index 5fb0aa0..b025f0f 100644 --- a/vinetrimmer/services/__init__.py +++ b/vinetrimmer/services/__init__.py @@ -6,30 +6,24 @@ from vinetrimmer.services.BaseService import BaseService SERVICE_MAP = {} -from vinetrimmer.services.amazon import Amazon -from vinetrimmer.services.appletvplus import AppleTVPlus -from vinetrimmer.services.max import Max -from vinetrimmer.services.netflix import Netflix +for service in os.listdir(os.path.dirname(__file__)): + if service.startswith("_") or not service.endswith(".py"): + continue -# Below dynamic imports fuck with compiling when using Nuitka - exec() call is the problem -#for service in os.listdir(os.path.dirname(__file__)): -# if service.startswith("_") or not service.endswith(".py"): -# continue + service = os.path.splitext(service)[0] -# service = os.path.splitext(service)[0] + if service in ("__init__", "BaseService"): + continue -# if service in ("__init__", "BaseService"): -# continue - -# with open(os.path.join(os.path.dirname(__file__), f"{service}.py"), encoding="utf-8") as fd: -# code = "" -# for line in fd.readlines(): -# if re.match(r"\s*(?:import(?! click)|from)\s", line): -# continue -# code += line -# if re.match(r"\s*super\(\)\.__init__\(", line): -# break -# exec(code) + with open(os.path.join(os.path.dirname(__file__), f"{service}.py"), encoding="utf-8") as fd: + code = "" + for line in fd.readlines(): + if re.match(r"\s*(?:import(?! click)|from)\s", line): + continue + code += line + if re.match(r"\s*super\(\)\.__init__\(", line): + break + exec(code) for x in copy(globals()).values(): if isinstance(x, type) and issubclass(x, BaseService) and x != BaseService: diff --git a/vinetrimmer/services/amazon.py b/vinetrimmer/services/amazon.py index b4c218a..d63248a 100644 --- a/vinetrimmer/services/amazon.py +++ b/vinetrimmer/services/amazon.py @@ -10,7 +10,6 @@ from collections import defaultdict from pathlib import Path from urllib.parse import urlencode, quote from typing import Union -from uuid import uuid4 import click import jsonpickle @@ -25,1303 +24,1145 @@ from vinetrimmer.objects.tracks import MenuTrack from vinetrimmer.services.BaseService import BaseService from vinetrimmer.utils import is_close_match from vinetrimmer.utils.Logger import Logger -from pywidevine import Device - +from vinetrimmer.utils.widevine.device import LocalDevice class Amazon(BaseService): - - """ - Service code for Amazon VOD (https://amazon.com) and Amazon Prime Video (https://primevideo.com). - - \b - Authorization: Cookies - Security: UHD@L1/SL3000 FHD@L3(ChromeCDM)/SL2000 SD@L3, Maintains their own license server like Netflix, be cautious. - - - \b - Region is chosen automatically based on domain extension found in cookies. - Prime Video specific code will be run if the ASIN is detected to be a prime video variant. - Use 'Amazon Video ASIN Display' for Tampermonkey addon for ASIN - https://greasyfork.org/en/scripts/381997-amazon-video-asin-display - - vt dl --list -z uk -q 1080 Amazon B09SLGYLK8 - """ - - ALIASES = ["AMZN", "amazon"] - TITLE_RE = r"^(?:https?://(?:www\.)?(?Pamazon\.(?Pcom|co\.uk|de|co\.jp)|primevideo\.com)(?:/.+)?/)?(?P[A-Z0-9]{10,}|amzn1\.dv\.gti\.[a-f0-9-]+)" # noqa: E501 - - REGION_TLD_MAP = { - "au": "com.au", - "br": "com.br", - "jp": "co.jp", - "mx": "com.mx", - "tr": "com.tr", - "gb": "co.uk", - "us": "com", - } - VIDEO_RANGE_MAP = { - "SDR": "None", - "HDR10": "Hdr10", - "DV": "DolbyVision", - } - - @staticmethod - @click.command(name="Amazon", short_help="https://amazon.com, https://primevideo.com", help=__doc__) - @click.argument("title", type=str, required=False) - @click.option("-b", "--bitrate", default="CBR", - type=click.Choice(["CVBR", "CBR", "CVBR+CBR"], case_sensitive=False), - help="Video Bitrate Mode to download in. CVBR=Constrained Variable Bitrate, CBR=Constant Bitrate.") - @click.option("-c", "--cdn", default=None, type=str, - help="CDN to download from, defaults to the CDN with the highest weight set by Amazon.") - # UHD, HD, SD. UHD only returns HEVC, ever, even for <=HD only content - @click.option("-vq", "--vquality", default="UHD", - type=click.Choice(["SD", "HD", "UHD"], case_sensitive=False), - help="Manifest quality to request.") - @click.option("-s", "--single", is_flag=True, default=False, - help="Force single episode/season instead of getting series ASIN.") - @click.option("-am", "--amanifest", default="H265", - type=click.Choice(["CVBR", "CBR", "H265"], case_sensitive=False), - help="Manifest to use for audio. Defaults to H265 if the video manifest is missing 640k audio.") - @click.option("-aq", "--aquality", default="SD", - type=click.Choice(["SD", "HD", "UHD"], case_sensitive=False), - help="Manifest quality to request for audio. Defaults to the same as --quality.") - @click.option("-ism", "--ism", is_flag=True, default=False, - help="Set manifest override to SmoothStreaming. Defaults to DASH w/o this flag.") - @click.pass_context - def cli(ctx, **kwargs): - return Amazon(ctx, **kwargs) - - def __init__(self, ctx, title, bitrate: str, cdn: str, vquality: str, single: bool, amanifest: str, aquality: str, ism: bool): - m = self.parse_title(ctx, title) - self.bitrate = bitrate - self.bitrate_source = ctx.get_parameter_source("bitrate") - self.cdn = cdn - self.vquality = vquality - self.vquality_source = ctx.get_parameter_source("vquality") - self.single = single - self.amanifest = amanifest - self.aquality = aquality - self.ism = ism - super().__init__(ctx) - - assert ctx.parent is not None - - self.vcodec = ctx.parent.params["vcodec"] or "H264" - self.range = ctx.parent.params["range_"] or "SDR" - self.chapters_only = ctx.parent.params["chapters_only"] - self.atmos = ctx.parent.params["atmos"] - self.quality = ctx.parent.params.get("quality") or 1080 - - self.cdm = ctx.obj.cdm - self.profile = ctx.obj.profile - - self.region: dict[str, str] = {} - self.endpoints: dict[str, str] = {} - self.device: dict[str, str] = {} - - self.pv = False - self.device_token = None - self.device_id: None - self.customer_id = None - self.client_id = "f22dbddb-ef2c-48c5-8876-bed0d47594fd" # browser client id - - if self.vquality_source != ParameterSource.COMMANDLINE: - if 0 < self.quality <= 576 and self.range == "SDR": - self.log.info(" + Setting manifest quality to SD") - self.vquality = "SD" - - if self.quality > 1080: - self.log.info(" + Setting manifest quality to UHD to be able to get 2160p video track") - self.vquality = "UHD" - self.vcodec = "H265" - - self.vquality = self.vquality or "HD" - - if self.bitrate_source != ParameterSource.COMMANDLINE: - if self.vcodec == "H265" and self.range == "SDR" and self.bitrate != "CVBR+CBR": - self.bitrate = "CVBR+CBR" - self.log.info(" + Changed bitrate mode to CVBR+CBR to be able to get H.265 SDR video track") - - if self.vquality == "UHD" and self.range != "SDR" and self.bitrate != "CBR": - self.bitrate = "CBR" - self.log.info(f" + Changed bitrate mode to CBR to be able to get highest quality UHD {self.range} video track") - - self.orig_bitrate = self.bitrate - - if self.ism: - self.manifestTypeTry = "SmoothStreaming" - self.log.info("Setting manifestType to SmoothStreaming (ISM)") - else: - self.manifestTypeTry = "DASH" - self.log.info("Setting manifestType to DASH (MPD)") - - self.configure() - - # Abstracted functions - - def get_titles(self): - res = self.session.get( - url=self.endpoints["details"], - params={ - "titleID": self.title, - "isElcano": "1", - "sections": ["Atf", "Btf"] - }, - headers={ - "Accept": "application/json" - } - ) - - if not res.ok: - raise self.log.exit(f"Unable to get title: {res.text} [{res.status_code}]") - - data = res.json()["widgets"] - product_details = data.get("productDetails", {}).get("detail") - - if not product_details: - error = res.json()["degradations"][0] - raise self.log.exit(f"Unable to get title: {error['message']} [{error['code']}]") - - titles = [] - - if data["pageContext"]["subPageType"] == "Movie": - card = data["productDetails"]["detail"] - titles.append(Title( - id_=card["catalogId"], - type_=Title.Types.MOVIE, - name=product_details["title"], - #year=card["releaseYear"], - year=card.get("releaseYear", ""), - # language is obtained afterward - original_lang=None, - source=self.ALIASES[0], - service_data=card - )) - else: - if ("titleContent" not in data.keys()) or (data["titleContent"] == []): - episodes = data["episodeList"]["episodes"] - for episode in episodes: - details = episode["detail"] - titles.append( - Title( - id_=details["catalogId"], - type_=Title.Types.TV, - name=product_details["parentTitle"], - season=data["productDetails"]["detail"]["seasonNumber"], - episode=episode["self"]["sequenceNumber"], - episode_name=details["title"], - # language is obtained afterward - original_lang=None, - source=self.ALIASES[0], - service_data=details, - ) - ) - if len(titles) == 25: - page_count = 1 - pagination_data = data.get('episodeList', {}).get('actions', {}).get('pagination', []) - token = next((quote(item.get('token')) for item in pagination_data if item.get('tokenType') == 'NextPage'), None) - while True: - page_count += 1 - res = self.session.get( - url=self.endpoints["getDetailWidgets"], - params={ - "titleID": self.title, - "isTvodOnRow": "1", - "widgets": f'[{{"widgetType":"EpisodeList","widgetToken":"{token}"}}]' - }, - headers={ - "Accept": "application/json" - } - ).json() - episodeList = res['widgets'].get('episodeList', {}) - for item in episodeList.get('episodes', []): - episode = int(item.get('self', {}).get('sequenceNumber', {})) - titles.append(Title( - id_=item["detail"]["catalogId"], - type_=Title.Types.TV, - name=product_details["parentTitle"], - season=product_details["seasonNumber"], - episode=episode, - episode_name=item["detail"]["title"], - # language is obtained afterward - original_lang=None, - source=self.ALIASES[0], - service_data=item - )) - pagination_data = res['widgets'].get('episodeList', {}).get('actions', {}).get('pagination', []) - token = next((quote(item.get('token')) for item in pagination_data if item.get('tokenType') == 'NextPage'), None) - if not token: - break - else: - cards = [ - x["detail"] - for x in data["titleContent"][0]["cards"] - if not self.single or - (self.single and self.title in data["self"]["asins"]) or (self.single and self.title in data["self"]["compactGTI"]) or - (self.single and self.title in x["self"]["asins"]) or (self.single and self.title == x["detail"]["catalogId"]) - ] - for card in cards: - episode_number = card.get("episodeNumber", 0) - if episode_number != 0: - titles.append(Title( - id_=card["catalogId"], - type_=Title.Types.TV, - name=product_details["parentTitle"], - season=product_details["seasonNumber"], - episode=episode_number, - episode_name=card["title"], - # language is obtained afterward - original_lang=None, - source=self.ALIASES[0], - service_data=card - )) - - if not self.single: - temp_title = self.title - temp_single = self.single - - self.single = True - for season in data.get('seasonSelector', []): - season_link = season["seasonLink"] - match = re.search(r'/([a-zA-Z0-9]+)\/ref=', season_link) #extract other season id using re - if match: - extracted_value = match.group(1) - if data["self"]["compactGTI"] == extracted_value: #skip entered asin season data and grab rest id's - continue - - self.title = extracted_value - for title in self.get_titles(): - titles.append(title) - - self.title = temp_title - self.single = temp_single - - - if titles: - # TODO: Needs playback permission on first title, title needs to be available - original_lang = self.get_original_language(self.get_manifest( - next((x for x in titles if x.type == Title.Types.MOVIE or x.episode > 0), titles[0]), - video_codec=self.vcodec, - bitrate_mode=self.bitrate, - quality="UHD", - ignore_errors=True - )) - if original_lang: - for title in titles: - title.original_lang = Language.get(original_lang) - else: - #self.log.warning(" - Unable to obtain the title's original language, setting 'en' default...") - for title in titles: - title.original_lang = Language.get("en") - - filtered_titles = [] - season_episode_count = defaultdict(int) - for title in titles: - key = (title.season, title.episode) - if season_episode_count[key] < 1: - filtered_titles.append(title) - season_episode_count[key] += 1 - - titles = filtered_titles - - return titles - - def get_tracks(self, title: Title) -> Tracks: - tracks = Tracks() - if self.chapters_only: - return [] - - manifest, chosen_manifest, tracks = self.get_best_quality(title) - - manifest = self.get_manifest( - title, - video_codec=self.vcodec, - bitrate_mode=self.bitrate, - quality="UHD", - hdr=self.range, - manifest_type=self.manifestTypeTry, - ignore_errors=False - - ) - - # Move rightsException termination here so that script can attempt continuing - if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: - self.log.error(" - The profile used does not have the rights to this title.") - return - - self.customer_id = manifest["returnedTitleRendition"]["selectedEntitlement"]["grantedByCustomerId"] - - default_url_set = manifest["playbackUrls"]["urlSets"][manifest["playbackUrls"]["defaultUrlSetId"]] - encoding_version = default_url_set["urls"]["manifest"]["encodingVersion"] - self.log.info(f" + Detected encodingVersion={encoding_version}") - - chosen_manifest = self.choose_manifest(manifest, self.cdn) - - try: - manifest_url = self.clean_mpd_url(chosen_manifest["avUrlInfoList"][0]["url"], False) - except: - chosen_manifest = default_url_set["urls"]["manifest"] - manifest_url = self.clean_mpd_url(chosen_manifest["url"], optimise=False) - - - self.log.debug(manifest_url) - self.log.info(" + Downloading Manifest") - - try: - tracks = Tracks([ - x for x in iter(Tracks.from_mpd( - url=manifest_url, - session=self.session, - source=self.ALIASES[0], - )) - ]) - except ValueError: - tracks = Tracks([ - x for x in iter(Tracks.from_ism( - url=manifest_url, - session=self.session, - source=self.ALIASES[0], - )) - ]) - except: - raise self.log.exit(f"Unsupported manifest type: {chosen_manifest['streamingTechnology']}\n{manifest_url}") - - need_separate_audio = ((self.aquality or self.vquality) != self.vquality - or self.amanifest == "CVBR" and (self.vcodec, self.bitrate) != ("H264", "CVBR") - or self.amanifest == "CBR" and (self.vcodec, self.bitrate) != ("H264", "CBR") - or self.amanifest == "H265" and self.vcodec != "H265" - or self.amanifest != "H265" and self.vcodec == "H265") - - if not need_separate_audio: - audios = defaultdict(list) - for audio in tracks.audios: - audios[audio.language].append(audio) - - for lang in audios: - if not any((x.bitrate or 0) >= 640000 for x in audios[lang]): - need_separate_audio = True - break - - if need_separate_audio and not self.atmos: - manifest_type = self.amanifest or "H265" - self.log.info(f"Getting audio from {manifest_type} manifest for potential higher bitrate or better codec") - audio_manifest = self.get_manifest( - title=title, - video_codec="H265" if manifest_type == "H265" else "H264", - bitrate_mode="CVBR" if manifest_type != "CBR" else "CBR", - quality=self.aquality or self.vquality, - hdr=None, - ignore_errors=True - ) - if not audio_manifest: - self.log.warning(f" - Unable to get {manifest_type} audio manifests, skipping") - elif not (chosen_audio_manifest := self.choose_manifest(audio_manifest, self.cdn)): - self.log.warning(f" - No {manifest_type} audio manifests available, skipping") - else: - audio_mpd_url = self.clean_mpd_url(chosen_audio_manifest["avUrlInfoList"][0]["url"], optimise=False) - self.log.debug(audio_mpd_url) - self.log.info(" + Downloading HEVC manifest") - - try: - audio_mpd = Tracks([ - x for x in iter(Tracks.from_mpd( - url=audio_mpd_url, - session=self.session, - source=self.ALIASES[0], - )) - ]) - except KeyError: - self.log.warning(f" - Title has no {self.amanifest} stream, cannot get higher quality audio") - else: - tracks.add(audio_mpd.audios, warn_only=True) # expecting possible dupes, ignore - - need_uhd_audio = self.atmos - - if not self.amanifest and ((self.aquality == "UHD" and self.vquality != "UHD") or not self.aquality): - audios = defaultdict(list) - for audio in tracks.audios: - audios[audio.language].append(audio) - for lang in audios: - if not any((x.bitrate or 0) >= 640000 for x in audios[lang]): - need_uhd_audio = True - break - - if need_uhd_audio and (self.config.get("device") or {}).get(self.profile, None): - self.log.info("Getting audio from UHD manifest for potential higher bitrate or better codec") - temp_device = self.device - temp_device_token = self.device_token - temp_device_id = self.device_id - uhd_audio_manifest = None - - - if (self.cdm.device.type == Device.Types.CHROME if "common_privacy_cert" in dir(self.cdm) else True) and self.quality < 2160: - self.log.info(f" + Switching to device to get UHD manifest") - self.register_device() - - - uhd_audio_manifest = self.get_manifest( - title=title, - video_codec="H265", - bitrate_mode="CVBR+CBR", - quality="UHD", - hdr="DV", # Needed for 576kbps Atmos sometimes - manifest_type="DASH", - ignore_errors=True - ) - - self.log.debug(uhd_audio_manifest) - - self.device = temp_device - self.device_token = temp_device_token - self.device_id = temp_device_id - - if not uhd_audio_manifest: - self.log.warning(f" - Unable to get UHD manifests, skipping") - elif not (chosen_uhd_audio_manifest := self.choose_manifest(uhd_audio_manifest, self.cdn)): - self.log.warning(f" - No UHD manifests available, skipping") - else: - uhd_audio_mpd_url = self.clean_mpd_url(chosen_uhd_audio_manifest["avUrlInfoList"][0]["url"], optimise=False) - self.log.debug(uhd_audio_mpd_url) - self.log.info(" + Downloading UHD manifest") - - try: - uhd_audio_mpd = Tracks([ - x for x in iter(Tracks.from_mpd( - url=uhd_audio_mpd_url, - session=self.session, - source=self.ALIASES[0], - )) - ]) - except ValueError: - uhd_audio_mpd = Tracks([ - x for x in iter(Tracks.from_ism( - url=uhd_audio_mpd_url, - session=self.session, - source=self.ALIASES[0], - )) - ]) - except KeyError: - self.log.warning(f" - Title has no UHD stream, cannot get higher quality audio") - - # replace the audio tracks with DV manifest version if atmos is present - if any(x for x in uhd_audio_mpd.audios if x.atmos): - tracks.audios = uhd_audio_mpd.audios - - for video in tracks.videos: - try: - video.hdr10 = chosen_manifest["hdrFormat"] == "Hdr10" - video.dv = chosen_manifest["hdrFormat"] == "DolbyVision" - except: - video.hdr10 = chosen_manifest["dynamicRange"] == "Hdr10" - video.dv = chosen_manifest["dynamicRange"] == "DolbyVision" - - - for audio in tracks.audios: - audio.descriptive = audio.extra[1].get("audioTrackSubtype") == "descriptive" or audio.extra[1].get("AudioTrackSubtype") == "descriptive" - # Amazon @lang is just the lang code, no dialect, @audioTrackId has it. - audio_track_id = audio.extra[1].get("audioTrackId") or audio.extra[1].get("AudioTrackId") - if audio_track_id: - audio.language = Language.get(audio_track_id.split("_")[0]) # e.g. es-419_ec3_blabla - - for sub in manifest.get("subtitleUrls", []) + manifest.get("forcedNarratives", []): - tracks.add(TextTrack( - id_=sub.get( - "timedTextTrackId", - f"{sub['languageCode']}_{sub['type']}_{sub['subtype']}_{sub['index']}" - ), - source=self.ALIASES[0], - url=os.path.splitext(sub["url"])[0] + ".srt", # DFXP -> SRT forcefully seems to work fine - # metadata - codec="srt", # sub["format"].lower(), - language=sub["languageCode"], - #is_original_lang=title.original_lang and is_close_match(sub["languageCode"], [title.original_lang]), - forced="forced" in sub["displayName"], - sdh=sub["type"].lower() == "sdh" # TODO: what other sub types? cc? forced? - ), warn_only=True) # expecting possible dupes, ignore - - return tracks - - def get_chapters(self, title: Title) -> list[MenuTrack]: - """Get chapters from Amazon's XRay Scenes API.""" - manifest = self.get_manifest( - title, - video_codec=self.vcodec, - bitrate_mode=self.bitrate, - quality="UHD", - manifest_type=self.manifestTypeTry, - hdr=self.range - ) - - if "xrayMetadata" in manifest: - xray_params = manifest["xrayMetadata"]["parameters"] - elif self.chapters_only: - xray_params = { - "pageId": "fullScreen", - "pageType": "xray", - "serviceToken": json.dumps({ - "consumptionType": "Streaming", - "deviceClass": "normal", - "playbackMode": "playback", - "vcid": manifest["returnedTitleRendition"]["contentId"], - }) - } - else: - return [] - - xray_params.update({ - "deviceID": self.device_id, - "deviceTypeID": self.config["device_types"]["browser"], # must be browser device type - "marketplaceID": self.region["marketplace_id"], - "gascEnabled": str(self.pv).lower(), - "decorationScheme": "none", - "version": "inception-v2", - "uxLocale": "en-US", - "featureScheme": "XRAY_WEB_2020_V1" - }) - - xray = self.session.get( - url=self.endpoints["xray"], - params=xray_params - ).json().get("page") - - if not xray: - return [] - - widgets = xray["sections"]["center"]["widgets"]["widgetList"] - - scenes = next((x for x in widgets if x["tabType"] == "scenesTab"), None) - if not scenes: - return [] - scenes = scenes["widgets"]["widgetList"][0]["items"]["itemList"] - - chapters = [] - - for scene in scenes: - chapter_title = scene["textMap"]["PRIMARY"] - match = re.search(r"(\d+\. |)(.+)", chapter_title) - if match: - chapter_title = match.group(2) - chapters.append(MenuTrack( - number=int(scene["id"].replace("/xray/scene/", "")), - title=chapter_title, - timecode=scene["textMap"]["TERTIARY"].replace("Starts at ", "") - )) - - return chapters - - def certificate(self, **_): - return self.config["certificate"] - - def license(self, challenge: Union[bytes, str], title: Title, **_): - lic_challenge = base64.b64encode(challenge).decode("utf-8") if isinstance(challenge, bytes) else base64.b64encode(challenge.encode("utf-8")).decode("utf-8") - self.log.debug(f"Challenge - {lic_challenge}") - - try: - lic = self.session.post( - url=self.endpoints["licence"], - params={ - "asin": title.id, - "consumptionType": "Streaming", - "desiredResources": "PlayReadyLicense", - "deviceTypeID": self.device["device_type"], - "deviceID": self.device_id, - "firmware": 1, - "gascEnabled": str(self.pv).lower(), - "marketplaceID": self.region["marketplace_id"], - "resourceUsage": "ImmediateConsumption", - "videoMaterialType": "Feature", - "operatingSystemName": "Linux" if self.vquality == "SD" else "Windows", - "operatingSystemVersion": "unknown" if self.vquality == "SD" else "10.0", - "customerID": self.customer_id, - "deviceDrmOverride": "Playready", - "deviceStreamingTechnologyOverride": "SmoothStreaming", - "deviceVideoQualityOverride": self.vquality, - "deviceHdrFormatsOverride": self.VIDEO_RANGE_MAP.get(self.range, "None"), - }, - headers={ - "Accept": "application/json", - "Content-Type": "application/x-www-form-urlencoded", - "Authorization": f"Bearer {self.device_token}" - }, - data={ - "playReadyChallenge": lic_challenge, # expects base64 - "includeHdcpTestKeyInLicense": "true" - } - ).json() - if "errorsByResource" in lic: - - error_code = lic["errorsByResource"]["PlayReadyLicense"] - self.log.debug(error_code) - if "errorCode" in error_code: - error_code = error_code["errorCode"] - elif "type" in error_code: - error_code = error_code["type"] - if error_code == "PRS.NoRights.AnonymizerIP": - raise self.log.exit(" - Amazon detected a Proxy/VPN and refused to return a license!") - message = lic["errorsByResource"]["PlayReadyLicense"]["message"] - raise self.log.exit(f" - Amazon reported an error during the License request: {message} [{error_code}]") - if "error" in lic: - error_code = lic["error"] - if "errorCode" in error_code: - error_code = error_code["errorCode"] - elif "type" in error_code: - error_code = error_code["type"] - if error_code == "PRS.NoRights.AnonymizerIP": - raise self.log.exit(" - Amazon detected a Proxy/VPN and refused to return a license!") - message = lic["error"]["message"] - raise self.log.exit(f" - Amazon reported an error during the License request: {message} [{error_code}]") - except: - lic = self.session.post( - url=self.endpoints["licence"], - params={ - "asin": title.id, - "consumptionType": "Streaming", - "desiredResources": "PlayReadyLicense", - "deviceTypeID": self.device["device_type"], - "deviceID": self.device_id, - "firmware": 1, - "gascEnabled": str(self.pv).lower(), - "marketplaceID": self.region["marketplace_id"], - "resourceUsage": "ImmediateConsumption", - "videoMaterialType": "Feature", - "operatingSystemName": "Linux" if self.vquality == "SD" else "Windows", - "operatingSystemVersion": "unknown" if self.vquality == "SD" else "10.0", - "customerID": self.customer_id, - "deviceDrmOverride": "Playready", #CENC or Playready - "deviceStreamingTechnologyOverride": "DASH", - "deviceVideoQualityOverride": self.vquality, - "deviceHdrFormatsOverride": self.VIDEO_RANGE_MAP.get(self.range, "None"), - }, - headers={ - "Accept": "application/json", - "Content-Type": "application/x-www-form-urlencoded", - "Authorization": f"Bearer {self.device_token}" - }, - data={ - "playReadyChallenge": lic_challenge, # expects base64 - "includeHdcpTestKeyInLicense": "true" - } - ).json() - if "errorsByResource" in lic: - - error_code = lic["errorsByResource"]["PlayReadyLicense"] - self.log.debug(error_code) - if "errorCode" in error_code: - error_code = error_code["errorCode"] - elif "type" in error_code: - error_code = error_code["type"] - if error_code == "PRS.NoRights.AnonymizerIP": - raise self.log.exit(" - Amazon detected a Proxy/VPN and refused to return a license!") - message = lic["errorsByResource"]["PlayReadyLicense"]["message"] - raise self.log.exit(f" - Amazon reported an error during the License request: {message} [{error_code}]") - if "error" in lic: - error_code = lic["error"] - if "errorCode" in error_code: - error_code = error_code["errorCode"] - elif "type" in error_code: - error_code = error_code["type"] - if error_code == "PRS.NoRights.AnonymizerIP": - raise self.log.exit(" - Amazon detected a Proxy/VPN and refused to return a license!") - message = lic["error"]["message"] - raise self.log.exit(f" - Amazon reported an error during the License request: {message} [{error_code}]") - #self.log.debug(lic["playReadyLicense"]["encodedLicenseResponse"]) - - return base64.b64decode(lic["playReadyLicense"]["encodedLicenseResponse"].encode("utf-8")).decode("utf-8") # Return Xml licence - - # Service specific functions - - def configure(self) -> None: - if len(self.title) > 10: - self.pv = True - - self.log.info("Getting Account Region") - self.region = self.get_region() - if not self.region: - raise self.log.exit(" - Failed to get Amazon Account region") - self.GEOFENCE.append(self.region["code"]) - self.log.info(f" + Region: {self.region['code']}") - - # endpoints must be prepared AFTER region data is retrieved - self.endpoints = self.prepare_endpoints(self.config["endpoints"], self.region) - - self.session.headers.update({ - "Origin": f"https://{self.region['base']}" - }) - - self.device = (self.config.get("device") or {}).get(self.profile, {}) - if (self.quality > 1080 or self.range != "SDR") and self.vcodec == "H265" and (self.cdm.device.type == Device.Types.CHROME if "common_privacy_cert" in dir(self.cdm) else True): - self.log.info(f"Using device to get UHD manifests") - self.register_device() - elif not self.device or self.vquality != "UHD" or (self.cdm.device.type == Device.Types.CHROME if "common_privacy_cert" in dir(self.cdm) else False): - # falling back to browser-based device ID - if not self.device: - self.log.warning( - "No Device information was provided for %s, using browser device...", - self.profile - ) - self.device_id = hashlib.sha224( - ("CustomerID" + self.session.headers["User-Agent"]).encode("utf-8") - ).hexdigest() - self.device = {"device_type": self.config["device_types"]["browser"]} - else: - self.register_device() - - def register_device(self) -> None: - self.device = (self.config.get("device") or {}).get(self.profile, {}) - device_cache_path = self.get_cache("device_tokens_{profile}_{hash}.json".format( - profile=self.profile, - hash=hashlib.md5(json.dumps(self.device).encode()).hexdigest()[0:6] - )) - self.device_token = self.DeviceRegistration( - device=self.device, - endpoints=self.endpoints, - log=self.log, - cache_path=device_cache_path, - session=self.session - ).bearer - self.device_id = self.device.get("device_serial") - if not self.device_id: - raise self.log.exit(f" - A device serial is required in the config, perhaps use: {os.urandom(8).hex()}") - - def get_region(self) -> dict: - domain_region = self.get_domain_region() - if not domain_region: - return {} - - region = self.config["regions"].get(domain_region) - if not region: - raise self.log.exit(f" - There's no region configuration data for the region: {domain_region}") - - region["code"] = domain_region - - if self.pv: - res = self.session.get("https://www.primevideo.com").text - match = re.search(r'ue_furl *= *([\'"])fls-(na|eu|fe)\.amazon\.[a-z.]+\1', res) - if match: - pv_region = match.group(2).lower() - else: - raise self.log.exit(" - Failed to get PrimeVideo region") - pv_region = {"na": "atv-ps"}.get(pv_region, f"atv-ps-{pv_region}") - region["base_manifest"] = f"{pv_region}.primevideo.com" - region["base"] = "www.primevideo.com" - - return region - - def get_domain_region(self): - """Get the region of the cookies from the domain.""" - tlds = [tldextract.extract(x.domain) for x in self.cookies if x.domain_specified] - tld = next((x.suffix for x in tlds if x.domain.lower() in ("amazon", "primevideo")), None) - if tld: - tld = tld.split(".")[-1] - return {"com": "us", "uk": "gb"}.get(tld, tld) - - def prepare_endpoint(self, name: str, uri: str, region: dict) -> str: - if name in ("browse", "playback", "licence", "xray"): - return f"https://{(region['base_manifest'])}{uri}" - if name in ("ontv", "devicelink", "details", "getDetailWidgets"): - if self.pv: - host = "www.primevideo.com" - else: - host = region["base"] - return f"https://{host}{uri}" - if name in ("codepair", "register", "token"): - return f"https://{self.config['regions']['us']['base_api']}{uri}" - raise ValueError(f"Unknown endpoint: {name}") - - def prepare_endpoints(self, endpoints: dict, region: dict) -> dict: - return {k: self.prepare_endpoint(k, v, region) for k, v in endpoints.items()} - - def choose_manifest(self, manifest: dict, cdn=None): - """Get manifest URL for the title based on CDN weight (or specified CDN).""" - if cdn: - cdn = cdn.lower() - manifest = next((x for x in manifest["audioVideoUrls"]["avCdnUrlSets"] if x["cdn"].lower() == cdn), {}) - if not manifest: - raise self.log.exit(f" - There isn't any manifests available on the CDN \"{cdn}\" for this title") - else: - manifest = next((x for x in sorted([x for x in manifest["audioVideoUrls"]["avCdnUrlSets"]], key=lambda x: int(x["cdnWeightsRank"]))), {}) - - return manifest - - def get_manifest( - self, - title: Title, - video_codec: str, - bitrate_mode: str, - quality: str, - manifest_type: str = None, - hdr=None, - ignore_errors: bool = False - ) -> dict: - res = self.session.get( - url=self.endpoints["playback"], - params={ - "asin": title.id, - "consumptionType": "Streaming", - "desiredResources": ",".join([ - "PlaybackUrls", - "AudioVideoUrls", - "CatalogMetadata", - "ForcedNarratives", - "SubtitlePresets", - "SubtitleUrls", - "TransitionTimecodes", - "TrickplayUrls", - "CuepointPlaylist", - "XRayMetadata", - "PlaybackSettings", - ]), - "deviceID": self.device_id, - "deviceTypeID": self.device["device_type"], - "firmware": 1, - "gascEnabled": str(self.pv).lower(), - "marketplaceID": self.region["marketplace_id"], - "resourceUsage": "CacheResources", - "videoMaterialType": "Feature", - "playerType": "html5", - "clientId": self.client_id, - **({ - "operatingSystemName": "Linux" if quality == "SD" else "Windows", - "operatingSystemVersion": "unknown" if quality == "SD" else "10.0", - } if not self.device_token else {}), - "deviceDrmOverride": "Playready" if manifest_type and (manifest_type == "SmoothStreaming") else "CENC", - "deviceStreamingTechnologyOverride": manifest_type if manifest_type else "DASH", - "deviceProtocolOverride": "Https", - "deviceVideoCodecOverride": video_codec, - "deviceBitrateAdaptationsOverride": bitrate_mode.replace("+", ","), - "deviceVideoQualityOverride": quality, - "deviceHdrFormatsOverride": self.VIDEO_RANGE_MAP.get(hdr, "None"), - "supportedDRMKeyScheme": "DUAL_KEY", # ? - "liveManifestType": "live,accumulating", # ? - "titleDecorationScheme": "primary-content", - "subtitleFormat": "TTMLv2", - "languageFeature": "MLFv2", # ? - "uxLocale": "en_US", - "xrayDeviceClass": "normal", - "xrayPlaybackMode": "playback", - "xrayToken": "XRAY_WEB_2020_V1", - "playbackSettingsFormatVersion": "1.0.0", - "playerAttributes": json.dumps({"frameRate": "HFR"}), - # possibly old/unused/does nothing: - "audioTrackId": "all", - }, - headers={ - "Authorization": f"Bearer {self.device_token}" if self.device_token else None, - }, - ) - try: - manifest = res.json() - except json.JSONDecodeError: - if ignore_errors: - return {} - - raise self.log.exit(" - Amazon didn't return JSON data when obtaining the Playback Manifest.") - - if "error" in manifest: - if ignore_errors: - return {} - raise self.log.exit(" - Amazon reported an error when obtaining the Playback Manifest.") - - # Commented out as we move the rights exception check elsewhere - # if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: - # if ignore_errors: - # return {} - # raise self.log.exit(" - The profile used does not have the rights to this title.") - - # Below checks ignore NoRights errors - - if ( - manifest.get("errorsByResource", {}).get("PlaybackUrls") and - manifest["errorsByResource"]["PlaybackUrls"].get("errorCode") != "PRS.NoRights.NotOwned" - ): - if ignore_errors: - return {} - error = manifest["errorsByResource"]["PlaybackUrls"] - raise self.log.exit(f" - Amazon had an error with the Playback Urls: {error['message']} [{error['errorCode']}]") - - if ( - manifest.get("errorsByResource", {}).get("AudioVideoUrls") and - manifest["errorsByResource"]["AudioVideoUrls"].get("errorCode") != "PRS.NoRights.NotOwned" - ): - if ignore_errors: - return {} - error = manifest["errorsByResource"]["AudioVideoUrls"] - raise self.log.exit(f" - Amazon had an error with the A/V Urls: {error['message']} [{error['errorCode']}]") - - #self.log.debug(manifest) - - return manifest - - @staticmethod - def get_original_language(manifest): - """Get a title's original language from manifest data.""" - try: - return next( - x["language"].replace("_", "-") - for x in manifest["catalogMetadata"]["playback"]["audioTracks"] - if x["isOriginalLanguage"] - ) - except (KeyError, StopIteration): - pass - - if "defaultAudioTrackId" in manifest.get("playbackUrls", {}): - try: - return manifest["playbackUrls"]["defaultAudioTrackId"].split("_")[0] - except IndexError: - pass - - try: - return sorted( - manifest["audioVideoUrls"]["audioTrackMetadata"], - key=lambda x: x["index"] - )[0]["languageCode"] - except (KeyError, IndexError): - pass - - return None - - @staticmethod - def clean_mpd_url(mpd_url, optimise): - """Clean up an Amazon MPD manifest url.""" - if optimise: - return mpd_url.replace("~", "") + "?encoding=segmentBase" - if match := re.match(r"(https?://.*/)d.?/.*~/(.*)", mpd_url): - return "".join(match.groups()) - elif match := re.match(r"(https?://.*/)d.?/.*\$.*?/(.*)", mpd_url): - return "".join(match.groups()) - else: - try: - mpd_url = "".join( - re.split(r"(?i)(/)", mpd_url)[:5] + re.split(r"(?i)(/)", mpd_url)[9:] - ) - except IndexError: - self.log.warning("Unable to parse manifest URL") - return mpd_url - - raise ValueError("Unable to parse manifest URL") - - def get_best_quality(self, title): - """ - Choose the best quality manifest from CBR / CVBR - """ - - track_list = [] - bitrates = [self.orig_bitrate] - - if self.vcodec != "H265": - bitrates = self.orig_bitrate.split('+') - - for bitrate in bitrates: - manifest = self.get_manifest( - title, - video_codec=self.vcodec, - bitrate_mode=bitrate, - quality="UHD", - hdr=self.range, - ignore_errors=False - ) - - if not manifest: - self.log.warning(f"Skipping {bitrate} manifest due to error") - continue - - # return three empty objects if a rightsException error exists to correlate to manifest, chosen_manifest, tracks - if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: - return None, None, None - - self.customer_id = manifest["returnedTitleRendition"]["selectedEntitlement"]["grantedByCustomerId"] - - default_url_set = manifest["playbackUrls"]["urlSets"][manifest["playbackUrls"]["defaultUrlSetId"]] - encoding_version = default_url_set["urls"]["manifest"]["encodingVersion"] - self.log.info(f" + Detected encodingVersion={encoding_version}") - - - #self.log.debug(manifest) - - chosen_manifest = self.choose_manifest(manifest, self.cdn) - - try: - mpd_url = self.clean_mpd_url(chosen_manifest["avUrlInfoList"][0]["url"], optimise=False) - except: - chosen_manifest = default_url_set["urls"]["manifest"] - mpd_url = self.clean_mpd_url(chosen_manifest["url"], optimise=False) - - self.log.debug(mpd_url) - self.log.info(f" + Downloading {bitrate} Manifest") - self.log.debug(f"Obtained Manifest Type: {chosen_manifest['streamingTechnology']}") - try: - tracks = Tracks([ - x for x in iter(Tracks.from_mpd( - url=mpd_url, - session=self.session, - source=self.ALIASES[0], - )) - ]) - except ValueError: - tracks = Tracks([ - x for x in iter(Tracks.from_ism( - url=mpd_url, - session=self.session, - source=self.ALIASES[0], - )) - ]) - except: - raise self.log.exit(f"Unsupported manifest type: {chosen_manifest['streamingTechnology']}\n{mpd_url}") - - for video in tracks.videos: - video.note = bitrate - - max_size = max(tracks.videos, key=lambda x: int(x.size or 0)).size - - - - track_list.append({ - 'bitrate': bitrate, - 'max_size': max_size, - 'manifest': manifest, - 'chosen_manifest': chosen_manifest, - 'tracks': tracks - }) - - best_quality = max(track_list, key=lambda x: x['max_size']) - - if len(self.bitrate.split('+')) > 1: - self.bitrate = best_quality['bitrate'] - self.log.info("Selected video manifest bitrate: %s", best_quality['bitrate']) - - return best_quality['manifest'], best_quality['chosen_manifest'], best_quality['tracks'] - - # Service specific classes - - class DeviceRegistration: - - def __init__(self, device: dict, endpoints: dict, cache_path: Path, session: requests.Session, log: Logger): - self.session = session - self.device = device - self.endpoints = endpoints - self.cache_path = Path(cache_path) - self.log = log - - self.device = {k: str(v) if not isinstance(v, str) else v for k, v in self.device.items()} - - self.bearer = None - if os.path.isfile(self.cache_path): - with open(self.cache_path, encoding="utf-8") as fd: - cache = jsonpickle.decode(fd.read()) - #self.device["device_serial"] = cache["device_serial"] - #if cache.get("expires_in", 0) > int(time.time()): - # # not expired, lets use - # self.log.info(" + Using cached device bearer") - # self.bearer = cache["access_token"] - #else: - # expired, refresh - self.log.info("Refreshing cached device bearer...") - refreshed_tokens = self.refresh(self.device, cache["refresh_token"], cache["access_token"]) - refreshed_tokens["refresh_token"] = cache["refresh_token"] - # expires_in seems to be in minutes, create a unix timestamp and add the minutes in seconds - refreshed_tokens["expires_in"] = int(time.time()) + int(refreshed_tokens["expires_in"]) - with open(self.cache_path, "w", encoding="utf-8") as fd: - fd.write(jsonpickle.encode(refreshed_tokens)) - self.bearer = refreshed_tokens["access_token"] - else: - self.log.info(" + Registering new device bearer") - self.bearer = self.register(self.device) - - def register(self, device: dict) -> dict: - """ - Register device to the account - :param device: Device data to register - :return: Device bearer tokens - """ - # OnTV csrf - csrf_token = self.get_csrf_token() - - # Code pair - code_pair = self.get_code_pair(device) - - # Device link - response = self.session.post( - url=self.endpoints["devicelink"], - headers={ - "Accept": "*/*", - "Accept-Language": "en-US,en;q=0.9,es-US;q=0.8,es;q=0.7", # needed? - "Content-Type": "application/x-www-form-urlencoded", - "Referer": self.endpoints["ontv"] - }, - params=urlencode({ - # any reason it urlencodes here? requests can take a param dict... - "ref_": "atv_set_rd_reg", - "publicCode": code_pair["public_code"], # public code pair - "token": csrf_token # csrf token - }) - ) - if response.status_code != 200: - raise self.log.exit(f"Unexpected response with the codeBasedLinking request: {response.text} [{response.status_code}]") - - # Register - response = self.session.post( - url=self.endpoints["register"], - headers={ - "Content-Type": "application/json", - "Accept-Language": "en-US" - }, - json={ - "auth_data": { - "code_pair": code_pair - }, - "registration_data": device, - "requested_token_type": ["bearer"], - "requested_extensions": ["device_info", "customer_info"] - }, - cookies=None # for some reason, may fail if cookies are present. Odd. - ) - if response.status_code != 200: - raise self.log.exit(f"Unable to register: {response.text} [{response.status_code}]") - bearer = response.json()["response"]["success"]["tokens"]["bearer"] - bearer["expires_in"] = int(time.time()) + int(bearer["expires_in"]) - - # Cache bearer - os.makedirs(os.path.dirname(self.cache_path), exist_ok=True) - with open(self.cache_path, "w", encoding="utf-8") as fd: - fd.write(jsonpickle.encode(bearer)) - - return bearer["access_token"] - - def refresh(self, device: dict, refresh_token: str, access_token: str) -> dict: - """ - json3 = { - 'app_name': 'ioBroker Alexa2', - 'app_version': '2.2.556530.0', - 'di.sdk.version': '6.12.4', - 'source_token': refresh_token, - 'package_name': 'com.amazon.echo', - 'di.hw.version': 'iPhone', - 'platform': 'iOS', - 'requested_token_type': 'access_token', - 'source_token_type': 'refresh_token', - 'di.os.name': 'iOS', - 'di.os.version': '16.6', - 'current_version': '6.12.4' - } - json4 = { - 'di.os.name': 'iOS', - 'app_version': '2.2.223830.0', - 'domain': '.' + 'api.amazon.com', - 'source_token': refresh_token, - 'requested_token_type': 'auth_cookies', - 'source_token_type': 'refresh_token', - 'di.hw.version': 'iPhone', - 'di.sdk.version': '6.10.0', - 'cookies': {}, - 'app_name': 'Amazon Alexa', - 'di.os.version': '11.4.1' - } - """ - # https://gitlab.com/keatontaylor/alexapy/-/commit/540b6333d973177bbc98e6ef39b00134f80ef0bb - - cookies = { - 'at-main': access_token, - } - headers = { - 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.223830.0/iOS/11.4.1/iPhone', - 'Accept-Language': 'en-US', - 'Accept-Charset': 'utf-8', - 'Connection': 'keep-alive', - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': '*/*' - } - data = { - 'di.os.name': 'iOS', - 'app_version': '2.2.223830.0', - 'domain': '.' + 'api.amazon.com', - 'source_token': refresh_token, - 'requested_token_type': 'auth_cookies', - 'source_token_type': 'refresh_token', - 'di.hw.version': 'iPhone', - 'di.sdk.version': '6.10.0', - 'app_name': 'Amazon Alexa', - 'di.os.version': '11.4.1' - } - - try: - # using the refresh token get the cookies needed for making calls to alexa.amazon.com - response = requests.post(url=self.endpoints["token"], headers=headers, cookies=cookies, data=data).json() - # Extract the cookies from the response - raw_cookies = response['response']['tokens']['cookies']['.amazon.com'] - except: - error = response['response']["error"] - self.cache_path.unlink(missing_ok=True) - raise self.log.exit(f"Error when refreshing cookies: {error['message']} [{error['code']}]") - - # Create a new cookies object to be used with requsts. - cookies = {} - for cookie in raw_cookies: - cookies[cookie['Name']] = cookie['Value'] - - headers = { - 'Content-Type': 'application/json; charset=utf-8', - 'Accept-Encoding': 'gzip, deflate, br', - 'Connection': 'keep-alive', - 'Accept': 'application/json; charset=utf-8', - 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 PitanguiBridge/2.2.389238.0-[HARDWARE=iPhone12_3][SOFTWARE=14.3]', - 'Accept-Language': 'en-US,en-US;q=1.0', - } - - json_data = { - **device, - 'requested_token_type': 'access_token', - 'source_token_type': 'refresh_token', - "source_token": refresh_token, - } # https://github.com/Sandmann79/xbmc/blob/dab17d913ee877d96115e6f799623bca158f3f24/plugin.video.amazon-test/resources/lib/login.py#L593 - - # make the call and print the response. - response = requests.post(url=self.endpoints["token"], headers=headers, cookies=cookies, json=json_data).json() - - if "error" in response: - self.cache_path.unlink(missing_ok=True) # Remove the cached device as its tokens have expired - raise self.log.exit( - f"Failed to refresh device token: {response['error_description']} [{response['error']}]" - ) - self.log.debug(response) - if response["token_type"] != "bearer": - raise self.log.exit("Unexpected returned refreshed token type") - - return response - - def get_csrf_token(self) -> str: - """ - On the amazon website, you need a token that is in the html page, - this token is used to register the device - :return: OnTV Page's CSRF Token - """ - res = self.session.get(self.endpoints["ontv"]) - response = res.text - if 'input type="hidden" name="appAction" value="SIGNIN"' in response: - raise self.log.exit( - "Cookies are signed out, cannot get ontv CSRF token. " - f"Expecting profile to have cookies for: {self.endpoints['ontv']}" - ) - for match in re.finditer(r"", response): - prop = json.loads(match.group(1)) - prop = prop.get("props", {}).get("codeEntry", {}).get("token") - if prop: - return prop - raise self.log.exit("Unable to get ontv CSRF token \n Navigate to /region/eu/ontv/code?ref_=atv_auth_red_aft, login and save cookies from that page to default.txt") - - def get_code_pair(self, device: dict) -> dict: - """ - Getting code pairs based on the device that you are using - :return: public and private code pairs - """ - res = self.session.post( - url=self.endpoints["codepair"], - headers={ - "Content-Type": "application/json", - "Accept-Language": "en-US" - }, - json={"code_data": device} - ).json() - if "error" in res: - raise self.log.exit(f"Unable to get code pair: {res['error_description']} [{res['error']}]") - return res + """ + Service code for Amazon VOD (https://amazon.com) and Amazon Prime Video (https://primevideo.com). + + \b + Authorization: Cookies + Security: UHD@L1 FHD@L3(ChromeCDM) SD@L3, Maintains their own license server like Netflix, be cautious. + + \b + Region is chosen automatically based on domain extension found in cookies. + Prime Video specific code will be run if the ASIN is detected to be a prime video variant. + Use 'Amazon Video ASIN Display' for Tampermonkey addon for ASIN + https://greasyfork.org/en/scripts/381997-amazon-video-asin-display + + vt dl --list -z uk -q 1080 Amazon B09SLGYLK8 + """ + + ALIASES = ["AMZN", "amazon"] + TITLE_RE = r"^(?:https?://(?:www\.)?(?Pamazon\.(?Pcom|co\.uk|de|co\.jp)|primevideo\.com)(?:/.+)?/)?(?P[A-Z0-9]{10,}|amzn1\.dv\.gti\.[a-f0-9-]+)" # noqa: E501 + + REGION_TLD_MAP = { + "au": "com.au", + "br": "com.br", + "jp": "co.jp", + "mx": "com.mx", + "tr": "com.tr", + "gb": "co.uk", + "us": "com", + } + VIDEO_RANGE_MAP = { + "SDR": "None", + "HDR10": "Hdr10", + "DV": "DolbyVision", + } + + @staticmethod + @click.command(name="Amazon", short_help="https://amazon.com, https://primevideo.com", help=__doc__) + @click.argument("title", type=str, required=False) + @click.option("-b", "--bitrate", default="CBR", + type=click.Choice(["CVBR", "CBR", "CVBR+CBR"], case_sensitive=False), + help="Video Bitrate Mode to download in. CVBR=Constrained Variable Bitrate, CBR=Constant Bitrate.") + @click.option("-c", "--cdn", default=None, type=str, + help="CDN to download from, defaults to the CDN with the highest weight set by Amazon.") + # UHD, HD, SD. UHD only returns HEVC, ever, even for <=HD only content + @click.option("-vq", "--vquality", default="HD", + type=click.Choice(["SD", "HD", "UHD"], case_sensitive=False), + help="Manifest quality to request.") + @click.option("-s", "--single", is_flag=True, default=False, + help="Force single episode/season instead of getting series ASIN.") + @click.option("-am", "--amanifest", default="H265", + type=click.Choice(["CVBR", "CBR", "H265"], case_sensitive=False), + help="Manifest to use for audio. Defaults to H265 if the video manifest is missing 640k audio.") + @click.option("-aq", "--aquality", default="SD", + type=click.Choice(["SD", "HD", "UHD"], case_sensitive=False), + help="Manifest quality to request for audio. Defaults to the same as --quality.") + @click.pass_context + def cli(ctx, **kwargs): + return Amazon(ctx, **kwargs) + + def __init__(self, ctx, title, bitrate: str, cdn: str, vquality: str, single: bool, amanifest: str, aquality: str): + m = self.parse_title(ctx, title) + self.bitrate = bitrate + self.bitrate_source = ctx.get_parameter_source("bitrate") + self.cdn = cdn + self.vquality = vquality + self.vquality_source = ctx.get_parameter_source("vquality") + self.single = single + self.amanifest = amanifest + self.aquality = aquality + super().__init__(ctx) + + assert ctx.parent is not None + + self.vcodec = ctx.parent.params["vcodec"] or "H264" + self.range = ctx.parent.params["range_"] or "SDR" + self.chapters_only = ctx.parent.params["chapters_only"] + self.atmos = ctx.parent.params["atmos"] + self.quality = ctx.parent.params.get("quality") or 1080 + + self.cdm = ctx.obj.cdm + self.profile = ctx.obj.profile + + self.region: dict[str, str] = {} + self.endpoints: dict[str, str] = {} + self.device: dict[str, str] = {} + + self.pv = False + self.device_token = None + self.device_id: None + self.customer_id = None + self.client_id = "f22dbddb-ef2c-48c5-8876-bed0d47594fd" # browser client id + + + + if self.vquality_source != ParameterSource.COMMANDLINE: + if 0 < self.quality <= 576 and self.range == "SDR": + self.log.info(" + Setting manifest quality to SD") + self.vquality = "SD" + + if self.quality > 1080: + self.log.info(" + Setting manifest quality to UHD to be able to get 2160p video track") + self.vquality = "UHD" + + self.vquality = self.vquality or "HD" + + if self.bitrate_source != ParameterSource.COMMANDLINE: + if self.vcodec == "H265" and self.range == "SDR" and self.bitrate != "CVBR+CBR": + self.bitrate = "CVBR+CBR" + self.log.info(" + Changed bitrate mode to CVBR+CBR to be able to get H.265 SDR video track") + + if self.vquality == "UHD" and self.range != "SDR" and self.bitrate != "CBR": + self.bitrate = "CBR" + self.log.info(f" + Changed bitrate mode to CBR to be able to get highest quality UHD {self.range} video track") + + self.orig_bitrate = self.bitrate + + self.configure() + + # Abstracted functions + + def get_titles(self): + res = self.session.get( + url=self.endpoints["details"], + params={ + "titleID": self.title, + "isElcano": "1", + "sections": ["Atf", "Btf"] + }, + headers={ + "Accept": "application/json" + } + ) + + if not res.ok: + raise self.log.exit(f"Unable to get title: {res.text} [{res.status_code}]") + + data = res.json()["widgets"] + product_details = data.get("productDetails", {}).get("detail") + + if not product_details: + error = res.json()["degradations"][0] + raise self.log.exit(f"Unable to get title: {error['message']} [{error['code']}]") + + titles = [] + + if data["pageContext"]["subPageType"] == "Movie": + card = data["productDetails"]["detail"] + titles.append(Title( + id_=card["catalogId"], + type_=Title.Types.MOVIE, + name=product_details["title"], + #year=card["releaseYear"], + year=card.get("releaseYear", ""), + # language is obtained afterward + original_lang=None, + source=self.ALIASES[0], + service_data=card + )) + else: + if data["titleContent"] == []: + episodes = data["episodeList"]["episodes"] + for episode in episodes: + details = episode["detail"] + titles.append( + Title( + id_=details["catalogId"], + type_=Title.Types.TV, + name=product_details["parentTitle"], + season=data["productDetails"]["detail"]["seasonNumber"], + episode=episode["self"]["sequenceNumber"], + episode_name=details["title"], + # language is obtained afterward + original_lang=None, + source=self.ALIASES[0], + service_data=details, + ) + ) + if len(titles) == 25: + page_count = 1 + pagination_data = data.get('episodeList', {}).get('actions', {}).get('pagination', []) + token = next((quote(item.get('token')) for item in pagination_data if item.get('tokenType') == 'NextPage'), None) + while True: + page_count += 1 + res = self.session.get( + url=self.endpoints["getDetailWidgets"], + params={ + "titleID": self.title, + "isTvodOnRow": "1", + "widgets": f'[{{"widgetType":"EpisodeList","widgetToken":"{token}"}}]' + }, + headers={ + "Accept": "application/json" + } + ).json() + episodeList = res['widgets'].get('episodeList', {}) + for item in episodeList.get('episodes', []): + episode = int(item.get('self', {}).get('sequenceNumber', {})) + titles.append(Title( + id_=item["detail"]["catalogId"], + type_=Title.Types.TV, + name=product_details["parentTitle"], + season=product_details["seasonNumber"], + episode=episode, + episode_name=item["detail"]["title"], + # language is obtained afterward + original_lang=None, + source=self.ALIASES[0], + service_data=item + )) + pagination_data = res['widgets'].get('episodeList', {}).get('actions', {}).get('pagination', []) + token = next((quote(item.get('token')) for item in pagination_data if item.get('tokenType') == 'NextPage'), None) + if not token: + break + else: + cards = [ + x["detail"] + for x in data["titleContent"][0]["cards"] + if not self.single or + (self.single and self.title in data["self"]["asins"]) or (self.single and self.title in data["self"]["compactGTI"]) or + (self.single and self.title in x["self"]["asins"]) or (self.single and self.title == x["detail"]["catalogId"]) + ] + for card in cards: + episode_number = card.get("episodeNumber", 0) + if episode_number != 0: + titles.append(Title( + id_=card["catalogId"], + type_=Title.Types.TV, + name=product_details["parentTitle"], + season=product_details["seasonNumber"], + episode=episode_number, + episode_name=card["title"], + # language is obtained afterward + original_lang=None, + source=self.ALIASES[0], + service_data=card + )) + + if not self.single: + temp_title = self.title + temp_single = self.single + + self.single = True + for season in data.get('seasonSelector', []): + season_link = season["seasonLink"] + match = re.search(r'/([a-zA-Z0-9]+)\/ref=', season_link) #extract other season id using re + if match: + extracted_value = match.group(1) + if data["self"]["compactGTI"] == extracted_value: #skip entered asin season data and grab rest id's + continue + + self.title = extracted_value + for title in self.get_titles(): + titles.append(title) + + self.title = temp_title + self.single = temp_single + + + if titles: + # TODO: Needs playback permission on first title, title needs to be available + original_lang = self.get_original_language(self.get_manifest( + next((x for x in titles if x.type == Title.Types.MOVIE or x.episode > 0), titles[0]), + video_codec=self.vcodec, + bitrate_mode=self.bitrate, + quality=self.vquality, + ignore_errors=True + )) + if original_lang: + for title in titles: + title.original_lang = Language.get(original_lang) + else: + #self.log.warning(" - Unable to obtain the title's original language, setting 'en' default...") + for title in titles: + title.original_lang = Language.get("en") + + filtered_titles = [] + season_episode_count = defaultdict(int) + for title in titles: + key = (title.season, title.episode) + if season_episode_count[key] < 1: + filtered_titles.append(title) + season_episode_count[key] += 1 + + titles = filtered_titles + + return titles + + def get_tracks(self, title: Title) -> Tracks: + tracks = Tracks() + if self.chapters_only: + return [] + + manifest, chosen_manifest, tracks = self.get_best_quality(title) + + manifest = self.get_manifest( + title, + video_codec=self.vcodec, + bitrate_mode=self.bitrate, + quality=self.vquality, + hdr=self.range, + ignore_errors=False + + ) + + # Move rightsException termination here so that script can attempt continuing + if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: + self.log.error(" - The profile used does not have the rights to this title.") + return + + self.customer_id = manifest["returnedTitleRendition"]["selectedEntitlement"]["grantedByCustomerId"] + + default_url_set = manifest["playbackUrls"]["urlSets"][manifest["playbackUrls"]["defaultUrlSetId"]] + encoding_version = default_url_set["urls"]["manifest"]["encodingVersion"] + self.log.info(f" + Detected encodingVersion={encoding_version}") + + chosen_manifest = self.choose_manifest(manifest, self.cdn) + + if not chosen_manifest: + raise self.log.exit(f"No manifests available") + + manifest_url = self.clean_mpd_url(chosen_manifest["avUrlInfoList"][0]["url"]) + self.log.debug(manifest_url) + self.log.info(" + Downloading Manifest") + + if chosen_manifest["streamingTechnology"] == "DASH": + tracks = Tracks([ + x for x in iter(Tracks.from_mpd( + url=manifest_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + elif chosen_manifest["streamingTechnology"] == "SmoothStreaming": + tracks = Tracks([ + x for x in iter(Tracks.from_ism( + url=manifest_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + else: + raise self.log.exit(f"Unsupported manifest type: {chosen_manifest['streamingTechnology']}") + + need_separate_audio = ((self.aquality or self.vquality) != self.vquality + or self.amanifest == "CVBR" and (self.vcodec, self.bitrate) != ("H264", "CVBR") + or self.amanifest == "CBR" and (self.vcodec, self.bitrate) != ("H264", "CBR") + or self.amanifest == "H265" and self.vcodec != "H265" + or self.amanifest != "H265" and self.vcodec == "H265") + + if not need_separate_audio: + audios = defaultdict(list) + + for audio in tracks.audios: + audio.descriptive = audio.extra[1].get("audioTrackSubtype") == "descriptive" + # Amazon @lang is just the lang code, no dialect, @audioTrackId has it. + audio_track_id = audio.extra[1].get("audioTrackId") + if audio_track_id: + audio.language = Language.get(audio_track_id.split("_")[0]) # e.g. es-419_ec3_blabla + # Remove any audio tracks with dialog boost! + if audio.extra[1] is not None and "boosteddialog" in audio.extra[1].get("audioTrackSubtype", ""): + tracks.audios.remove(audio) + + for audio in tracks.audios: + audios[audio.language].append(audio) + + for lang in audios: + if not any((x.bitrate or 0) >= 640000 for x in audios[lang]): + need_separate_audio = True + break + + if need_separate_audio and not self.atmos: + manifest_type = self.amanifest or "H265" + self.log.info(f"Getting audio from {manifest_type} manifest for potential higher bitrate or better codec") + audio_manifest = self.get_manifest( + title=title, + video_codec="H265" if manifest_type == "H265" else "H264", + bitrate_mode="CVBR" if manifest_type != "CBR" else "CBR", + quality=self.aquality or self.vquality, + hdr=None, + ignore_errors=True + ) + if not audio_manifest: + self.log.warning(f" - Unable to get {manifest_type} audio manifests, skipping") + elif not (chosen_audio_manifest := self.choose_manifest(audio_manifest, self.cdn)): + self.log.warning(f" - No {manifest_type} audio manifests available, skipping") + else: + audio_mpd_url = self.clean_mpd_url(chosen_audio_manifest["avUrlInfoList"][0]["url"]) + self.log.debug(audio_mpd_url) + self.log.info(" + Downloading HEVC manifest") + + try: + audio_mpd = Tracks([ + x for x in iter(Tracks.from_mpd( + url=audio_mpd_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + except KeyError: + self.log.warning(f" - Title has no {self.amanifest} stream, cannot get higher quality audio") + else: + tracks.add(audio_mpd.audios, warn_only=True) # expecting possible dupes, ignore + + need_uhd_audio = self.atmos + + if not self.amanifest and ((self.aquality == "UHD" and self.vquality != "UHD") or not self.aquality): + audios = defaultdict(list) + for audio in tracks.audios: + audios[audio.language].append(audio) + for lang in audios: + if not any((x.bitrate or 0) >= 640000 for x in audios[lang]): + need_uhd_audio = True + break + + if need_uhd_audio and (self.config.get("device") or {}).get(self.profile, None): + self.log.info("Getting audio from UHD manifest for potential higher bitrate or better codec") + temp_device = self.device + temp_device_token = self.device_token + temp_device_id = self.device_id + uhd_audio_manifest = None + + try: + if self.quality < 2160 or (self.cdm.device.type == LocalDevice.Types.CHROME): + self.log.info(f" + Switching to device to get UHD manifest") + self.register_device() + + uhd_audio_manifest = self.get_manifest( + title=title, + video_codec="H265", + bitrate_mode="CVBR+CBR", + quality="UHD", + hdr="DV", # Needed for 576kbps Atmos sometimes + ignore_errors=False + ) + except: + self.log.exit() + + + self.device = temp_device + self.device_token = temp_device_token + self.device_id = temp_device_id + + if not uhd_audio_manifest: + self.log.warning(f" - Unable to get UHD manifests, skipping") + elif not (chosen_uhd_audio_manifest := self.choose_manifest(uhd_audio_manifest, self.cdn)): + self.log.warning(f" - No UHD manifests available, skipping") + else: + uhd_audio_mpd_url = self.clean_mpd_url(chosen_uhd_audio_manifest["avUrlInfoList"][0]["url"]) + self.log.debug(uhd_audio_mpd_url) + self.log.info(" + Downloading UHD manifest") + + try: + uhd_audio_mpd = Tracks([ + x for x in iter(Tracks.from_mpd( + url=uhd_audio_mpd_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + except KeyError: + self.log.warning(f" - Title has no UHD stream, cannot get higher quality audio") + else: + # replace the audio tracks with DV manifest version if atmos is present + if any(x for x in uhd_audio_mpd.audios if x.atmos): + tracks.audios = uhd_audio_mpd.audios + + for video in tracks.videos: + video.hdr10 = chosen_manifest["hdrFormat"] == "Hdr10" + video.dv = chosen_manifest["hdrFormat"] == "DolbyVision" + + for audio in tracks.audios: + audio.descriptive = audio.extra[1].get("audioTrackSubtype") == "descriptive" + # Amazon @lang is just the lang code, no dialect, @audioTrackId has it. + audio_track_id = audio.extra[1].get("audioTrackId") + if audio_track_id: + audio.language = Language.get(audio_track_id.split("_")[0]) # e.g. es-419_ec3_blabla + + if audio.extra[1] is not None and "boosteddialog" in audio.extra[1].get("audioTrackSubtype", ""): + tracks.audios.remove(audio) + + + for sub in manifest.get("subtitleUrls", []) + manifest.get("forcedNarratives", []): + tracks.add(TextTrack( + id_=sub.get( + "timedTextTrackId", + f"{sub['languageCode']}_{sub['type']}_{sub['subtype']}_{sub['index']}" + ), + source=self.ALIASES[0], + url=os.path.splitext(sub["url"])[0] + ".srt", # DFXP -> SRT forcefully seems to work fine + # metadata + codec="srt", # sub["format"].lower(), + language=sub["languageCode"], + #is_original_lang=title.original_lang and is_close_match(sub["languageCode"], [title.original_lang]), + forced="forced" in sub["displayName"], + sdh=sub["type"].lower() == "sdh" # TODO: what other sub types? cc? forced? + ), warn_only=True) # expecting possible dupes, ignore + + return tracks + + + def get_chapters(self, title: Title) -> list[MenuTrack]: + """Get chapters from Amazon's XRay Scenes API.""" + manifest = self.get_manifest( + title, + video_codec=self.vcodec, + bitrate_mode=self.bitrate, + quality=self.vquality, + hdr=self.range + ) + + if "xrayMetadata" in manifest: + xray_params = manifest["xrayMetadata"]["parameters"] + elif self.chapters_only: + xray_params = { + "pageId": "fullScreen", + "pageType": "xray", + "serviceToken": json.dumps({ + "consumptionType": "Streaming", + "deviceClass": "normal", + "playbackMode": "playback", + "vcid": manifest["returnedTitleRendition"]["contentId"], + }) + } + else: + return [] + + xray_params.update({ + "deviceID": self.device_id, + "deviceTypeID": self.config["device_types"]["browser"], # must be browser device type + "marketplaceID": self.region["marketplace_id"], + "gascEnabled": str(self.pv).lower(), + "decorationScheme": "none", + "version": "inception-v2", + "uxLocale": "en-US", + "featureScheme": "XRAY_WEB_2020_V1" + }) + + xray = self.session.get( + url=self.endpoints["xray"], + params=xray_params + ).json().get("page") + + if not xray: + return [] + + widgets = xray["sections"]["center"]["widgets"]["widgetList"] + + scenes = next((x for x in widgets if x["tabType"] == "scenesTab"), None) + if not scenes: + return [] + scenes = scenes["widgets"]["widgetList"][0]["items"]["itemList"] + + chapters = [] + + for scene in scenes: + chapter_title = scene["textMap"]["PRIMARY"] + match = re.search(r"(\d+\. |)(.+)", chapter_title) + if match: + chapter_title = match.group(2) + chapters.append(MenuTrack( + number=int(scene["id"].replace("/xray/scene/", "")), + title=chapter_title, + timecode=scene["textMap"]["TERTIARY"].replace("Starts at ", "") + )) + + return chapters + + def certificate(self, **_): + return self.config["certificate"] + + def license(self, challenge: Union[bytes, str], title: Title, **_): + lic = self.session.post( + url=self.endpoints["licence"], + params={ + "asin": title.id, + "consumptionType": "Streaming", + "desiredResources": "PlayReadyLicense", + "deviceTypeID": self.device["device_type"], + "deviceID": self.device_id, + "firmware": 1, + "gascEnabled": str(self.pv).lower(), + "marketplaceID": self.region["marketplace_id"], + "resourceUsage": "ImmediateConsumption", + "videoMaterialType": "Feature", + "operatingSystemName": "Linux" if self.vquality == "SD" else "Windows", + "operatingSystemVersion": "unknown" if self.vquality == "SD" else "10.0", + "customerID": self.customer_id, + "deviceDrmOverride": "CENC", + "deviceStreamingTechnologyOverride": "DASH", # "SmoothStreaming" + "deviceVideoQualityOverride": self.vquality, + "deviceHdrFormatsOverride": self.VIDEO_RANGE_MAP.get(self.range, "None"), + }, + headers={ + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": f"Bearer {self.device_token}" + }, + data={ + "playReadyChallenge": base64.b64encode(challenge).decode("utf-8") if isinstance(challenge, bytes) else base64.b64encode(challenge.encode("ascii")).decode("utf-8"), # expects base64 + "includeHdcpTestKeyInLicense": "true" + } + ).json() + if "errorsByResource" in lic: + print(lic["errorsByResource"]) + error_code = lic["errorsByResource"]["playReadyLicense"] + if "errorCode" in error_code: + error_code = error_code["errorCode"] + elif "type" in error_code: + error_code = error_code["type"] + if error_code == "PRS.NoRights.AnonymizerIP": + raise self.log.exit(" - Amazon detected a Proxy/VPN and refused to return a license!") + message = lic["errorsByResource"]["playReadyLicense"]["message"] + raise self.log.exit(f" - Amazon reported an error during the License request: {message} [{error_code}]") + if "error" in lic: + error_code = lic["error"] + if "errorCode" in error_code: + error_code = error_code["errorCode"] + elif "type" in error_code: + error_code = error_code["type"] + if error_code == "PRS.NoRights.AnonymizerIP": + raise self.log.exit(" - Amazon detected a Proxy/VPN and refused to return a license!") + message = lic["error"]["message"] + raise self.log.exit(f" - Amazon reported an error during the License request: {message} [{error_code}]") + #self.log.info(lic["playReadyLicense"]["encodedLicenseResponse"]) + return lic["playReadyLicense"]["encodedLicenseResponse"] + + # Service specific functions + + def configure(self) -> None: + if len(self.title) > 10: + self.pv = True + + self.log.info("Getting Account Region") + self.region = self.get_region() + if not self.region: + raise self.log.exit(" - Failed to get Amazon Account region") + self.GEOFENCE.append(self.region["code"]) + self.log.info(f" + Region: {self.region['code']}") + + # endpoints must be prepared AFTER region data is retrieved + self.endpoints = self.prepare_endpoints(self.config["endpoints"], self.region) + + self.session.headers.update({ + "Origin": f"https://{self.region['base']}" + }) + + self.device = (self.config.get("device") or {}).get(self.profile, {}) + if (self.quality > 1080 or self.range != "SDR") and self.vcodec == "H265" and (self.cdm.device.type == LocalDevice.Types.CHROME if "common_privacy_cert" in dir(self.cdm) else False): + self.log.info(f"Using device to get UHD manifests") + self.register_device() + elif not self.device or self.vquality != "UHD" or (self.cdm.device.type == LocalDevice.Types.CHROME if "common_privacy_cert" in dir(self.cdm) else False): + # falling back to browser-based device ID + if not self.device: + self.log.warning( + "No Device information was provided for %s, using browser device...", + self.profile + ) + self.device_id = hashlib.sha224( + ("CustomerID" + self.session.headers["User-Agent"]).encode("utf-8") + ).hexdigest() + self.device = {"device_type": self.config["device_types"]["browser"]} + else: + self.register_device() + + def register_device(self) -> None: + self.device = (self.config.get("device") or {}).get(self.profile, {}) + device_cache_path = self.get_cache("device_tokens_{profile}_{hash}.json".format( + profile=self.profile, + hash=hashlib.md5(json.dumps(self.device).encode()).hexdigest()[0:6] + )) + self.device_token = self.DeviceRegistration( + device=self.device, + endpoints=self.endpoints, + log=self.log, + cache_path=device_cache_path, + session=self.session + ).bearer + self.device_id = self.device.get("device_serial") + if not self.device_id: + raise self.log.exit(f" - A device serial is required in the config, perhaps use: {os.urandom(8).hex()}") + + def get_region(self) -> dict: + domain_region = self.get_domain_region() + if not domain_region: + return {} + + region = self.config["regions"].get(domain_region) + if not region: + raise self.log.exit(f" - There's no region configuration data for the region: {domain_region}") + + region["code"] = domain_region + + if self.pv: + res = self.session.get("https://www.primevideo.com").text + match = re.search(r'ue_furl *= *([\'"])fls-(na|eu|fe)\.amazon\.[a-z.]+\1', res) + if match: + pv_region = match.group(2).lower() + else: + raise self.log.exit(" - Failed to get PrimeVideo region") + pv_region = {"na": "atv-ps"}.get(pv_region, f"atv-ps-{pv_region}") + region["base_manifest"] = f"{pv_region}.primevideo.com" + region["base"] = "www.primevideo.com" + + return region + + def get_domain_region(self): + """Get the region of the cookies from the domain.""" + tlds = [tldextract.extract(x.domain) for x in self.cookies if x.domain_specified] + tld = next((x.suffix for x in tlds if x.domain.lower() in ("amazon", "primevideo")), None) + if tld: + tld = tld.split(".")[-1] + return {"com": "us", "uk": "gb"}.get(tld, tld) + + def prepare_endpoint(self, name: str, uri: str, region: dict) -> str: + if name in ("browse", "playback", "licence", "xray"): + return f"https://{(region['base_manifest'])}{uri}" + if name in ("ontv", "devicelink", "details", "getDetailWidgets"): + if self.pv: + host = "www.primevideo.com" + else: + host = region["base"] + return f"https://{host}{uri}" + if name in ("codepair", "register", "token"): + return f"https://{self.config['regions']['us']['base_api']}{uri}" + raise ValueError(f"Unknown endpoint: {name}") + + def prepare_endpoints(self, endpoints: dict, region: dict) -> dict: + return {k: self.prepare_endpoint(k, v, region) for k, v in endpoints.items()} + + def choose_manifest(self, manifest: dict, cdn=None): + """Get manifest URL for the title based on CDN weight (or specified CDN).""" + if cdn: + cdn = cdn.lower() + manifest = next((x for x in manifest["audioVideoUrls"]["avCdnUrlSets"] if x["cdn"].lower() == cdn), {}) + if not manifest: + raise self.log.exit(f" - There isn't any DASH manifests available on the CDN \"{cdn}\" for this title") + else: + manifest = next((x for x in sorted([x for x in manifest["audioVideoUrls"]["avCdnUrlSets"]], key=lambda x: int(x["cdnWeightsRank"]))), {}) + + return manifest + + def get_manifest( + self, title: Title, video_codec: str, bitrate_mode: str, quality: str, hdr=None, + ignore_errors: bool = False + ) -> dict: + res = self.session.get( + url=self.endpoints["playback"], + params={ + "asin": title.id, + "consumptionType": "Streaming", + "desiredResources": ",".join([ + "PlaybackUrls", + "AudioVideoUrls", + "CatalogMetadata", + "ForcedNarratives", + "SubtitlePresets", + "SubtitleUrls", + "TransitionTimecodes", + "TrickplayUrls", + "CuepointPlaylist", + "XRayMetadata", + "PlaybackSettings", + ]), + "deviceID": self.device_id, + "deviceTypeID": self.device["device_type"], + "firmware": 1, + "gascEnabled": str(self.pv).lower(), + "marketplaceID": self.region["marketplace_id"], + "resourceUsage": "CacheResources", + "videoMaterialType": "Feature", + "playerType": "html5", + "clientId": self.client_id, + **({ + "operatingSystemName": "Linux" if quality == "SD" else "Windows", + "operatingSystemVersion": "unknown" if quality == "SD" else "10.0", + } if not self.device_token else {}), + "deviceDrmOverride": "CENC", + "deviceStreamingTechnologyOverride": "DASH", # or SmoothStreaming + "deviceProtocolOverride": "Https", + "deviceVideoCodecOverride": video_codec, + "deviceBitrateAdaptationsOverride": bitrate_mode.replace("+", ","), + "deviceVideoQualityOverride": quality, + "deviceHdrFormatsOverride": self.VIDEO_RANGE_MAP.get(hdr, "None"), + "supportedDRMKeyScheme": "DUAL_KEY", # ? + "liveManifestType": "live,accumulating", # ? + "titleDecorationScheme": "primary-content", + "subtitleFormat": "TTMLv2", + "languageFeature": "MLFv2", # ? + "uxLocale": "en_US", + "xrayDeviceClass": "normal", + "xrayPlaybackMode": "playback", + "xrayToken": "XRAY_WEB_2020_V1", + "playbackSettingsFormatVersion": "1.0.0", + "playerAttributes": json.dumps({"frameRate": "HFR"}), + # possibly old/unused/does nothing: + "audioTrackId": "all", + }, + headers={ + "Authorization": f"Bearer {self.device_token}" if self.device_token else None, + }, + ) + try: + manifest = res.json() + except json.JSONDecodeError: + if ignore_errors: + return {} + + raise self.log.exit(" - Amazon didn't return JSON data when obtaining the Playback Manifest.") + + if "error" in manifest: + if ignore_errors: + return {} + raise self.log.exit(" - Amazon reported an error when obtaining the Playback Manifest.") + + # Commented out as we move the rights exception check elsewhere + # if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: + # if ignore_errors: + # return {} + # raise self.log.exit(" - The profile used does not have the rights to this title.") + + # Below checks ignore NoRights errors + + if ( + manifest.get("errorsByResource", {}).get("PlaybackUrls") and + manifest["errorsByResource"]["PlaybackUrls"].get("errorCode") != "PRS.NoRights.NotOwned" + ): + if ignore_errors: + return {} + error = manifest["errorsByResource"]["PlaybackUrls"] + raise self.log.exit(f" - Amazon had an error with the Playback Urls: {error['message']} [{error['errorCode']}]") + + if ( + manifest.get("errorsByResource", {}).get("AudioVideoUrls") and + manifest["errorsByResource"]["AudioVideoUrls"].get("errorCode") != "PRS.NoRights.NotOwned" + ): + if ignore_errors: + return {} + error = manifest["errorsByResource"]["AudioVideoUrls"] + raise self.log.exit(f" - Amazon had an error with the A/V Urls: {error['message']} [{error['errorCode']}]") + + return manifest + + @staticmethod + def get_original_language(manifest): + """Get a title's original language from manifest data.""" + try: + return next( + x["language"].replace("_", "-") + for x in manifest["catalogMetadata"]["playback"]["audioTracks"] + if x["isOriginalLanguage"] + ) + except (KeyError, StopIteration): + pass + + if "defaultAudioTrackId" in manifest.get("playbackUrls", {}): + try: + return manifest["playbackUrls"]["defaultAudioTrackId"].split("_")[0] + except IndexError: + pass + + try: + return sorted( + manifest["audioVideoUrls"]["audioTrackMetadata"], + key=lambda x: x["index"] + )[0]["languageCode"] + except (KeyError, IndexError): + pass + + return None + + def clean_mpd_url(self, mpd_url, optimise=True): + #self.log.debug(f"MPD URL: {mpd_url}, optimise: {optimise}") + """Clean up an Amazon MPD manifest url.""" + if 'akamaihd.net' in mpd_url: + match = re.search(r'[^/]*\$[^/]*/', mpd_url) + if match: + dollar_sign_part = match.group(0) + mpd_url = mpd_url.replace(dollar_sign_part, '', 1) + return mpd_url + + if optimise: + return mpd_url.replace("~", "") + "?encoding=segmentBase" + else: + if match := re.match(r"(https?://.*/)d.?/.*~/(.*)", mpd_url): + self.log.debug(f"returned: {''.join(match.groups())}") + return "".join(match.groups()) + elif match := re.match(r"(https?://.*/)d.?/.*\$.*?/(.*)", mpd_url): + self.log.debug(f"returned: {''.join(match.groups())}") + return "".join(match.groups()) + elif match := re.match(r"(https?://.*/).*\$.*?/(.*)", mpd_url): + self.log.debug(f"returned: {''.join(match.groups())}") + return "".join(match.groups()) + elif match := re.split(r"(?i)(/)", mpd_url)[:5] + re.split(r"(?i)(/)", mpd_url)[9:]: + self.log.debug(f"returned: {''.join(match.groups())}") + return "".join(match.groups()) + raise ValueError("Unable to parse MPD URL") + + + + def get_best_quality(self, title): + """ + Choose the best quality manifest from CBR / CVBR + """ + + track_list = [] + bitrates = [self.orig_bitrate] + + if self.vcodec != "H265": + bitrates = self.orig_bitrate.split('+') + + for bitrate in bitrates: + manifest = self.get_manifest( + title, + video_codec=self.vcodec, + bitrate_mode=bitrate, + quality=self.vquality, + hdr=self.range, + ignore_errors=False + ) + + if not manifest: + self.log.warning(f"Skipping {bitrate} manifest due to error") + continue + + # return three empty objects if a rightsException error exists to correlate to manifest, chosen_manifest, tracks + if "rightsException" in manifest["returnedTitleRendition"]["selectedEntitlement"]: + return None, None, None + + self.customer_id = manifest["returnedTitleRendition"]["selectedEntitlement"]["grantedByCustomerId"] + + default_url_set = manifest["playbackUrls"]["urlSets"][manifest["playbackUrls"]["defaultUrlSetId"]] + encoding_version = default_url_set["urls"]["manifest"]["encodingVersion"] + self.log.info(f" + Detected encodingVersion={encoding_version}") + + chosen_manifest = self.choose_manifest(manifest, self.cdn) + + if not chosen_manifest: + self.log.warning(f"No {bitrate} manifests available") + continue + + mpd_url = self.clean_mpd_url(chosen_manifest["avUrlInfoList"][0]["url"]) + self.log.debug(mpd_url) + + + + if chosen_manifest["streamingTechnology"] == "DASH": + self.log.info(f" + Downloading {bitrate} MPD") + tracks = Tracks([ + x for x in iter(Tracks.from_mpd( + url=mpd_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + elif chosen_manifest["streamingTechnology"] == "SmoothStreaming": + self.log.info(f" + Downloading {bitrate} ISM") + tracks = Tracks([ + x for x in iter(Tracks.from_ism( + url=mpd_url, + session=self.session, + source=self.ALIASES[0], + )) + ]) + else: + raise self.log.exit(f"Unsupported manifest type: {chosen_manifest['streamingTechnology']}") + + for video in tracks.videos: + video.note = bitrate + + max_size = max(tracks.videos, key=lambda x: int(x.size or 0)).size + + track_list.append({ + 'bitrate': bitrate, + 'max_size': max_size, + 'manifest': manifest, + 'chosen_manifest': chosen_manifest, + 'tracks': tracks + }) + + best_quality = max(track_list, key=lambda x: x['max_size']) + + if len(self.bitrate.split('+')) > 1: + self.bitrate = best_quality['bitrate'] + self.log.info("Selected video manifest bitrate: %s", best_quality['bitrate']) + + return best_quality['manifest'], best_quality['chosen_manifest'], best_quality['tracks'] + + # Service specific classes + + class DeviceRegistration: + + def __init__(self, device: dict, endpoints: dict, cache_path: Path, session: requests.Session, log: Logger): + self.session = session + self.device = device + self.endpoints = endpoints + self.cache_path = cache_path + self.log = log + + self.device = {k: str(v) if not isinstance(v, str) else v for k, v in self.device.items()} + + self.bearer = None + if os.path.isfile(self.cache_path): + with open(self.cache_path, encoding="utf-8") as fd: + cache = jsonpickle.decode(fd.read()) + #self.device["device_serial"] = cache["device_serial"] + if cache.get("expires_in", 0) > int(time.time()): + # not expired, lets use + self.log.info(" + Using cached device bearer") + self.bearer = cache["access_token"] + else: + # expired, refresh + self.log.info("Cached device bearer expired, refreshing...") + refreshed_tokens = self.refresh(self.device, cache["refresh_token"]) + refreshed_tokens["refresh_token"] = cache["refresh_token"] + # expires_in seems to be in minutes, create a unix timestamp and add the minutes in seconds + refreshed_tokens["expires_in"] = int(time.time()) + int(refreshed_tokens["expires_in"]) + with open(self.cache_path, "w", encoding="utf-8") as fd: + fd.write(jsonpickle.encode(refreshed_tokens)) + self.bearer = refreshed_tokens["access_token"] + else: + self.log.info(" + Registering new device bearer") + self.bearer = self.register(self.device) + + def register(self, device: dict) -> dict: + """ + Register device to the account + :param device: Device data to register + :return: Device bearer tokens + """ + # OnTV csrf + csrf_token = self.get_csrf_token() + + # Code pair + code_pair = self.get_code_pair(device) + + # Device link + response = self.session.post( + url=self.endpoints["devicelink"], + headers={ + "Accept": "*/*", + "Accept-Language": "en-US,en;q=0.9,es-US;q=0.8,es;q=0.7", # needed? + "Content-Type": "application/x-www-form-urlencoded", + "Referer": self.endpoints["ontv"] + }, + params=urlencode({ + # any reason it urlencodes here? requests can take a param dict... + "ref_": "atv_set_rd_reg", + "publicCode": code_pair["public_code"], # public code pair + "token": csrf_token # csrf token + }) + ) + if response.status_code != 200: + raise self.log.exit(f"Unexpected response with the codeBasedLinking request: {response.text} [{response.status_code}]") + + # Register + response = self.session.post( + url=self.endpoints["register"], + headers={ + "Content-Type": "application/json", + "Accept-Language": "en-US" + }, + json={ + "auth_data": { + "code_pair": code_pair + }, + "registration_data": device, + "requested_token_type": ["bearer"], + "requested_extensions": ["device_info", "customer_info"] + }, + cookies=None # for some reason, may fail if cookies are present. Odd. + ) + if response.status_code != 200: + raise self.log.exit(f"Unable to register: {response.text} [{response.status_code}]") + bearer = response.json()["response"]["success"]["tokens"]["bearer"] + bearer["expires_in"] = int(time.time()) + int(bearer["expires_in"]) + + # Cache bearer + os.makedirs(os.path.dirname(self.cache_path), exist_ok=True) + with open(self.cache_path, "w", encoding="utf-8") as fd: + fd.write(jsonpickle.encode(bearer)) + + return bearer["access_token"] + + def refresh(self, device: dict, refresh_token: str) -> dict: + response = self.session.post( + url=self.endpoints["token"], + json={ + "app_name": device["app_name"], + "app_version": device["app_version"], + "source_token_type": "refresh_token", + "source_token": refresh_token, + "requested_token_type": "access_token" + } + ).json() + if "error" in response: + self.cache_path.unlink(missing_ok=True) # Remove the cached device as its tokens have expired + raise self.log.exit( + f"Failed to refresh device token: {response['error_description']} [{response['error']}]" + ) + if response["token_type"] != "bearer": + raise self.log.exit("Unexpected returned refreshed token type") + return response + + def get_csrf_token(self) -> str: + """ + On the amazon website, you need a token that is in the html page, + this token is used to register the device + :return: OnTV Page's CSRF Token + """ + res = self.session.get(self.endpoints["ontv"]) + response = res.text + if 'input type="hidden" name="appAction" value="SIGNIN"' in response: + raise self.log.exit( + "Cookies are signed out, cannot get ontv CSRF token. " + f"Expecting profile to have cookies for: {self.endpoints['ontv']}" + ) + for match in re.finditer(r"", response): + prop = json.loads(match.group(1)) + prop = prop.get("props", {}).get("codeEntry", {}).get("token") + if prop: + return prop + raise self.log.exit("Unable to get ontv CSRF token \n Navigate to /region/eu/ontv/code?ref_=atv_auth_red_aft, login and save cookies from that page to default.txt") + + def get_code_pair(self, device: dict) -> dict: + """ + Getting code pairs based on the device that you are using + :return: public and private code pairs + """ + res = self.session.post( + url=self.endpoints["codepair"], + headers={ + "Content-Type": "application/json", + "Accept-Language": "en-US" + }, + json={"code_data": device} + ).json() + if "error" in res: + raise self.log.exit(f"Unable to get code pair: {res['error_description']} [{res['error']}]") + return res diff --git a/vinetrimmer/services/appletvplus.py b/vinetrimmer/services/appletvplus.py index 8abd723..96039e6 100644 --- a/vinetrimmer/services/appletvplus.py +++ b/vinetrimmer/services/appletvplus.py @@ -3,6 +3,7 @@ import json import re from datetime import datetime from urllib.parse import unquote +from typing import Dict, List import click import m3u8 @@ -27,10 +28,7 @@ class AppleTVPlus(BaseService): """ ALIASES = ["ATVP", "appletvplus", "appletv+"] - TITLE_RE = [ - r"^(?:https?://tv\.apple\.com(?:/[a-z]{2})?/(?:movie|show|episode)/[a-z0-9-]+/)?(?Pumc\.cmc\.[a-z0-9]+)", - r"^(?:https?://tv\.apple\.com(?:/[a-z]{2})?/(?:movie|show|episode|sporting-event)/[a-z0-9-]+/)?(?Pumc\.cse\.[a-z0-9]+)", - ] + TITLE_RE = r"^(?:https?://tv\.apple\.com(?:/[a-z]{2})?/(?:movie|show|episode)/[a-z0-9-]+/)?(?Pumc\.cmc\.[a-z0-9]+)" # noqa: E501 VIDEO_CODEC_MAP = { "H264": ["avc"], @@ -45,48 +43,36 @@ class AppleTVPlus(BaseService): @staticmethod @click.command(name="AppleTVPlus", short_help="https://tv.apple.com") @click.argument("title", type=str, required=False) - @click.option("-c", "--condensed", is_flag=True, default=False, - help="To retrieve Condensed Recap instead of default Full Game") @click.pass_context def cli(ctx, **kwargs): return AppleTVPlus(ctx, **kwargs) - def __init__(self, ctx: click.Context, title, condensed: bool): + def __init__(self, ctx, title): super().__init__(ctx) self.parse_title(ctx, title) + self.quality = ctx.parent.params["quality"] self.vcodec = ctx.parent.params["vcodec"] self.acodec = ctx.parent.params["acodec"] self.alang = ctx.parent.params["alang"] + self.range = ctx.parent.params["range_"] self.subs_only = ctx.parent.params["subs_only"] self.extra_server_parameters = None - self.condensed = condensed - self.type = 1 # show = 0, movie = 1, sporting-event = 2 + if ("HDR" in self.range) or (self.range == "DV") or ((self.quality << 1080) if self.quality else False): + self.log.info(" - Setting Video codec to H265 to get UHD") + self.vcodec = "H265" self.configure() def get_titles(self): r = None - for i in range(3): + for i in range(2): try: - self.params = { - 'utsk': '6e3013c6d6fae3c2::::::9318c17fb39d6b9c', - 'caller': 'web', - 'sf': self.storefront, - 'v': '82' if self.type == 2 else '46', - 'pfm': 'appletv', - 'mfr': 'Apple', - 'locale': 'en-US', - 'l': 'en', - 'ctx_brand': 'tvs.sbd.4000', - 'count': '100', - 'skip': '0', - } r = self.session.get( - url=self.config["endpoints"]["title"].format(type={0: "shows", 1: "movies", 2: "sporting-events"}[i], id=self.title), - params=self.params + url=self.config["endpoints"]["title"].format(type={0: "shows", 1: "movies"}[i], id=self.title), + params=self.config["device"] ) except requests.HTTPError as e: if e.response.status_code != 404: @@ -101,32 +87,22 @@ class AppleTVPlus(BaseService): except json.JSONDecodeError: raise ValueError(f"Failed to load title manifest: {r.text}") + self.log.debug(title_information) + if title_information["type"] == "Movie": return Title( id_=self.title, type_=Title.Types.MOVIE, name=title_information["title"], - #year=datetime.utcfromtimestamp(title_information["releaseDate"] / 1000).year, - original_lang=title_information["originalSpokenLanguages"][0]["locale"], - source=self.ALIASES[0], - service_data=title_information - ) - elif title_information["type"] == "SportingEvent": - self.type = 2 - return Title( - id_=self.title, - type_=Title.Types.MOVIE, - name=title_information["title"], - #year=datetime.utcfromtimestamp(title_information["releaseDate"] / 1000).year, - #original_lang=title_information["originalSpokenLanguages"][0]["locale"], + year=datetime.utcfromtimestamp(title_information["releaseDate"] / 1000).year, + original_lang=title_information["originalSpokenLanguages"][0]["locale"] if "originalSpokenLanguages" in title_information.keys() else "und", source=self.ALIASES[0], service_data=title_information ) else: - self.type = 0 r = self.session.get( url=self.config["endpoints"]["tv_episodes"].format(id=self.title), - params=self.params + params=self.config["device"] ) try: episodes = r.json()["data"]["episodes"] @@ -140,45 +116,30 @@ class AppleTVPlus(BaseService): season=episode["seasonNumber"], episode=episode["episodeNumber"], episode_name=episode.get("title"), - original_lang=title_information["originalSpokenLanguages"][0]["locale"], + original_lang=title_information["originalSpokenLanguages"][0]["locale"] if "originalSpokenLanguages" in title_information.keys() else "und", source=self.ALIASES[0], service_data=episode ) for episode in episodes] def get_tracks(self, title): - self.params = { - 'utsk': '6e3013c6d6fae3c2::::::9318c17fb39d6b9c', - 'caller': 'web', - 'sf': self.storefront, - 'v': '82', - 'pfm': 'appletv', - 'mfr': 'Apple', - 'locale': 'en-US', - 'l': 'en', - 'ctx_brand': 'tvs.sbd.4000', - 'count': '100', - 'skip': '0', - } - r = self.session.get(url=self.config["endpoints"]["title"].format(type={0: "shows", 1: "movies", 2: "sporting-events"}[self.type], id=self.title), - params=self.params + r = self.session.get( + url=self.config["endpoints"]["manifest"].format(id=title.service_data["id"]), + params=self.config["device"] ) try: stream_data = r.json() - #print(stream_data) except json.JSONDecodeError: raise ValueError(f"Failed to load stream data: {r.text}") - stream_data = stream_data["data"]["playables"] - if self.condensed == True: - tvs_sbd = list(stream_data.keys())[1] - else: - tvs_sbd = list(stream_data.keys())[0] - stream_data = stream_data[tvs_sbd] + stream_data = stream_data["data"]["content"]["playables"][0] + if not stream_data["isEntitledToPlay"]: + self.log.debug(stream_data) raise self.log.exit(" - User is not entitled to play this title") self.extra_server_parameters = stream_data["assets"]["fpsKeyServerQueryParameters"] - - r = requests.get(url=stream_data["assets"]["hlsUrl"], headers={'User-Agent': 'AppleTV6,2/11.1'}) + self.log.debug(self.extra_server_parameters) + self.log.debug(stream_data["assets"]["hlsUrl"]) + r = requests.get(url=stream_data["assets"]["hlsUrl"], headers={'User-Agent': 'ATVE/1.1 FireOS/6.2.6.8 build/4A93 maker/Amazon model/FireTVStick4K FW/NS6268/2315'}) res = r.text tracks = Tracks.from_m3u8( @@ -203,8 +164,10 @@ class AppleTVPlus(BaseService): #if isinstance(track, VideoTrack) and not tracks.subtitles: # track.needs_ccextractor_first = True if isinstance(track, VideoTrack): + track.needs_proxy = False track.encrypted = True if isinstance(track, AudioTrack): + track.needs_proxy = False track.encrypted = True bitrate = re.search(r"&g=(\d+?)&", track_data.uri) if not bitrate: @@ -215,6 +178,7 @@ class AppleTVPlus(BaseService): raise ValueError(f"Unable to get a bitrate value for Track {track.id}") track.codec = track.codec.replace("_vod", "") if isinstance(track, TextTrack): + track.needs_proxy = True track.codec = "vtt" tracks.videos = [x for x in tracks.videos if (x.codec or "")[:3] in self.VIDEO_CODEC_MAP[self.vcodec]] @@ -240,13 +204,7 @@ class AppleTVPlus(BaseService): ) ]) except: - return Tracks([ - # multiple CDNs, only want one - x for x in tracks - #if any( - # cdn in as_list(x.url)[0].split("?")[1].split("&") for cdn in ["cdn=ak", "cdn=vod-ak-aoc.tv.apple.com"] - #) - ]) + return Tracks([x for x in tracks]) def get_chapters(self, title): return [] @@ -254,44 +212,78 @@ class AppleTVPlus(BaseService): def certificate(self, **_): return None # will use common privacy cert + def license(self, challenge, track, **_): - try: - res = self.session.post( - url=self.config["endpoints"]["license"], - json={ - 'streaming-request': { - 'version': 1, - 'streaming-keys': [ + if (isinstance(challenge, bytes) and challenge.startswith(b' List: + + # poetry run vt dl -al en -sl en --selected --proxy http://192.168.0.99:9766 --keys -q 2160 -v H265 ATVP + # poetry run vt dl -al en -sl en --selected --proxy http://192.168.0.99:9766 --keys -q 2160 -v H265 -r DV ATVP + + urls = [] + params = self.config["device"] + params["utscf"] = "OjAAAAEAAAAAAAAAEAAAACMA" + params["nextToken"] = str(start) + + r = None + try: + r = self.session.get( + url=self.config["endpoints"]["homecanvas"], + params=params + ) + except requests.HTTPError as e: + if e.response.status_code != 404: + raise + + if not r: + raise self.log.exit(f" - Canvas endpoint errored out") + try: + shelves = r.json()["data"]["canvas"]["shelves"] + except json.JSONDecodeError: + raise ValueError(f"Failed to load title manifest: {r.text}") + + # TODO - Add check userisentitledtoplay before appending url + for shelf in shelves: + items = shelf["items"] + for item in items: + urls.append(item["url"]) + + url_regex = re.compile(r"^(?:https?://tv\.apple\.com(?:/[a-z]{2})?/(?Pmovie|show|episode)/[a-z0-9-]+/)?(?Pumc\.cmc\.[a-z0-9]+)") + + for url in urls: + match = url_regex.match(url) + + if match: + # Extract the title type and ID + title_type = match.group("type") + "s" # None if not present + title_id = match.group("id") + + else: + continue + + r = None + try: + r = self.session.get( + url=self.config["endpoints"]["title"].format(type=title_type, id=title_id), + params=self.config["device"] + ) + except requests.HTTPError as e: + if e.response.status_code != 404: + raise + if not r: + raise self.log.exit(f" - Title ID {self.title!r} could not be found.") + try: + shelves = r.json()["data"]["canvas"]["shelves"] + except json.JSONDecodeError: + raise ValueError(f"Failed to load title manifest: {r.text}") + + for shelf in shelves: + if "uts.col.ContentRelated" in shelf["id"]: + items = shelf["items"] + for item in items: + if item["url"] not in urls: + # TODO - Add check userisentitledtoplay before appending url + urls.append(item["url"]) + + if len(urls) >= length: + break + + return urls \ No newline at end of file diff --git a/vinetrimmer/services/appletvplus1.py b/vinetrimmer/services/appletvplus1.py index 81d3b4f..594b86e 100644 --- a/vinetrimmer/services/appletvplus1.py +++ b/vinetrimmer/services/appletvplus1.py @@ -2,7 +2,7 @@ import click from base64 import b64encode, b64decode from datetime import datetime, timedelta -from json import loads, JSONDecodeError +from json import loads from m3u8 import loads as m3u8loads from re import search from requests import get, HTTPError @@ -13,15 +13,10 @@ from vinetrimmer.objects import Title, Tracks, VideoTrack, AudioTrack, TextTrack from vinetrimmer.services.BaseService import BaseService - class AppleTVPlus(BaseService): """ Service code for Apple's TV Plus streaming service (https://tv.apple.com). - \b - WIP: decrypt and removal of bumper/dub cards - - \b Authorization: Cookies Security: Playready: @@ -40,16 +35,9 @@ class AppleTVPlus(BaseService): TITLE_RE = r"^(?:https?://tv\.apple\.com(?:/[a-z]{2})?/(?:movie|show|episode)/[a-z0-9-]+/)?(?Pumc\.cmc\.[a-z0-9]+)" # noqa: E501 + VIDEO_CODEC_MAP = {"H264": ["avc"], "H265": ["hvc", "hev", "dvh"]} - VIDEO_CODEC_MAP = { - "H264": ["avc"], - "H265": ["hvc", "hev", "dvh"] - } - AUDIO_CODEC_MAP = { - "AAC": ["HE", "stereo"], - "AC3": ["ac3"], - "EC3": ["ec3", "atmos"] - } + AUDIO_CODEC_MAP = {"AAC": ["HE", "stereo"], "AC3": ["ac3"], "EC3": ["ec3", "atmos"]} @staticmethod @click.command(name="AppleTVPlus", short_help="https://tv.apple.com") @@ -66,15 +54,9 @@ class AppleTVPlus(BaseService): self.alang = ctx.parent.params["alang"] self.subs_only = ctx.parent.params["subs_only"] self.vcodec = ctx.parent.params["vcodec"] - self.range = ctx.parent.params["range_"] or "SDR" - self.quality = ctx.parent.params["quality"] or 1080 self.extra_server_parameters: Optional[dict] = None - if ("HDR" in self.range) or ("DV" in self.range) or ((self.quality > 1080) if self.quality else False): - self.log.info(" - Setting Video codec to H265 to get UHD") - self.vcodec = "H265" - self.configure() def get_titles(self) -> list[Title]: @@ -84,61 +66,88 @@ class AppleTVPlus(BaseService): for i in range(2): try: req = self.session.get( - url=self.config["endpoints"]["title"].format(type={0: "shows", 1: "movies"}[i], id=self.title), - params=self.config["device"] + url=self.config["endpoints"]["title"].format( + types={0: "shows", 1: "movies"}[i], cid=self.title + ), + params={ + "caller": "web", + "count": "100", + "ctx_brand": "tvs.sbd.4000", + "l": "en", + "locale": "en-US", + "mfr": "Apple", + "pfm": "appletv", + "sf": "143441", + "skip": "0", + "utsk": "6e3013c6d6fae3c2::::::235656c069bb0efb", + "v": "56", + }, ) except HTTPError as error: if error.response.status_code != 404: raise - else: - if req.ok: - break - if not req: - raise self.log.exit(f" - Title ID {self.title!r} could not be found.") - try: - title = req.json()["data"]["content"] - except json.JSONDecodeError: - raise ValueError(f"Failed to load title manifest: {r.text}") + title = req.json() - self.log.debug(title) - - if title["type"] == "Movie": + if title["data"]["content"]["type"] == "Movie": titles.append( Title( id_=self.title, type_=Title.Types.MOVIE, - name=title["title"], - year=datetime.utcfromtimestamp(title["releaseDate"] / 1000).year, - original_lang=title["originalSpokenLanguages"][0]["locale"] if "originalSpokenLanguages" in title.keys() else "und", + name=title["data"]["content"]["title"], + year=( + datetime(1970, 1, 1) + + timedelta( + milliseconds=title["data"]["content"]["releaseDate"] + ) + ).year, + original_lang=title["data"]["content"]["originalSpokenLanguages"][ + 0 + ]["locale"], source=self.ALIASES[0], - service_data=title, + service_data=title["data"]["content"], ) ) else: req = self.session.get( - url=self.config["endpoints"]["tv_episodes"].format(id=self.title), - params=self.config["device"] + url=self.config["endpoints"]["episode"].format(cid=self.title), + params={ + "caller": "web", + "count": "100", + "ctx_brand": "tvs.sbd.4000", + "l": "en", + "locale": "en-US", + "mfr": "Apple", + "pfm": "appletv", + "sf": "143441", + "skip": "0", + "utsk": "6e3013c6d6fae3c2::::::235656c069bb0efb", + "v": "56", + }, ) - try: - episodes = req.json()["data"]["episodes"] - except JSONDecodeError: - raise ValueError(f"Failed to load episodes list: {req.text}") + data = req.json() - for episode in episodes: + for episode in data["data"]["episodes"]: titles.append( Title( id_=self.title, type_=Title.Types.TV, name=episode["showTitle"], - year=datetime.utcfromtimestamp(title["releaseDate"] / 1000).year, + year=( + datetime(1970, 1, 1) + + timedelta( + milliseconds=title["data"]["content"]["releaseDate"] + ) + ).year, season=episode["seasonNumber"], episode=episode["episodeNumber"], episode_name=episode.get("title"), - original_lang=title["originalSpokenLanguages"][0]["locale"] if "originalSpokenLanguages" in title.keys() else "und", + original_lang=title["data"]["content"][ + "originalSpokenLanguages" + ][0]["locale"], source=self.ALIASES[0], service_data=episode, ) @@ -150,30 +159,38 @@ class AppleTVPlus(BaseService): tracks = Tracks() req = self.session.get( - url=self.config["endpoints"]["manifest"].format(id=title.service_data["id"]), - params=self.config["device"] + url=self.config["endpoints"]["manifest.xml"].format( + cid=title.service_data["id"] + ), + params={ + "caller": "web", + "count": "100", + "ctx_brand": "tvs.sbd.4000", + "l": "en", + "locale": "en-US", + "mfr": "Apple", + "pfm": "appletv", + "sf": "143441", + "skip": "0", + "utsk": "6e3013c6d6fae3c2::::::235656c069bb0efb", + "v": "56", + }, ) - - try: - data = req.json() - except JSONDecodeError: - raise ValueError(f"Failed to load stream data: {req.text}") + data = req.json() stream_data = data["data"]["content"]["playables"][0] if not stream_data["isEntitledToPlay"]: - self.log.debug(stream_data) raise self.log.exit(" - User is not entitled to play this title") - self.extra_server_parameters = stream_data["assets"]["fpsKeyServerQueryParameters"] - - self.log.debug(self.extra_server_parameters) - self.log.debug(stream_data["assets"]["hlsUrl"]) + self.extra_server_parameters = stream_data["assets"][ + "fpsKeyServerQueryParameters" + ] req = get( url=stream_data["assets"]["hlsUrl"], - headers={"User-Agent": "AppleTV6,2/11.1"}, # 'ATVE/1.1 FireOS/6.2.6.8 build/4A93 maker/Amazon model/FireTVStick4K FW/NS6268/2315' + headers={"User-Agent": "AppleTV6,2/11.1"}, ) tracks.add( @@ -182,28 +199,14 @@ class AppleTVPlus(BaseService): ) ) - for track in tracks: track.extra = {"url": track.url, "manifest.xml": track.extra} - track_data = track.extra["manifest.xml"] if isinstance(track, VideoTrack): track.encrypted = True track.needs_ccextractor_first = True - track.needs_proxy = False elif isinstance(track, AudioTrack): track.encrypted = True - track.needs_proxy = False - bitrate = search(pattern=r"&g=(\d+?)&", string=track_data.uri ) - if not bitrate: - bitrate = re.search(r"_gr(\d+)_", track_data.uri) # new - if bitrate: - track.bitrate = int(bitrate[1][-3::]) * 1000 - - else: - raise ValueError(f"Unable to get a bitrate value for Track {track.id}") - - track.codec = track.codec.replace("_vod", "") elif isinstance(track, TextTrack): track.codec = "vtt" @@ -211,7 +214,9 @@ class AppleTVPlus(BaseService): quality = None for line in req.text.splitlines(): if line.startswith("#--"): - quality = {"SD": 480, "HD720": 720, "HD": 1080, "UHD": 2160}.get(line.split()[2]) + quality = {"SD": 480, "HD720": 720, "HD": 1080, "UHD": 2160}.get( + line.split()[2] + ) elif not line.startswith("#"): track = next( @@ -220,6 +225,23 @@ class AppleTVPlus(BaseService): if track: track.extra["quality"] = quality + for track in tracks: + track_data = track.extra["manifest.xml"] + if isinstance(track, AudioTrack): + bitrate = search( + pattern=r"&g=(\d+?)&", + string=track_data.uri, + ) + if bitrate: + track.bitrate = int(bitrate[1][-3::]) * 1000 + + else: + raise ValueError( + f"Unable to get a bitrate value for Track {track.id}" + ) + + track.codec = track.codec.replace("_vod", "") + tracks.videos = [ x for x in tracks.videos @@ -245,16 +267,7 @@ class AppleTVPlus(BaseService): or not x.sdh ] - try: - return Tracks([ - # multiple CDNs, only want one - x for x in tracks - if any( - cdn in as_list(x.url)[0].split("?")[1].split("&") for cdn in ["cdn=ak", "cdn=vod-ak-aoc.tv.apple.com"] - ) - ]) - except: - return Tracks([x for x in tracks]) + return tracks def get_chapters(self, title: Title) -> list[MenuTrack]: chapters = list() @@ -273,23 +286,23 @@ class AppleTVPlus(BaseService): "version": 1, "streaming-keys": [ { - "challenge": b64encode(challenge.encode("UTF-8")).decode("UTF-8"), + "challenge": b64encode( + challenge.encode("UTF-8") + ).decode("UTF-8"), "key-system": "com.microsoft.playready", - "uri": f"data:text/plain;charset=UTF-16;base64,{track.pssh}", + "uri": f"data:text/plain;charset=UTF-16;base64,{track.pssh_playready}", "id": 1, "lease-action": "start", "adamId": self.extra_server_parameters["adamId"], "isExternal": True, - "svcId": self.extra_server_parameters["svcId"], + "svcId": "tvs.vds.4078", }, ], }, }, - params=self.config["device"] ) except HTTPError as error: - self.log.warn(e) if not error.response.text: raise self.log.exit(" - No License Returned!") @@ -321,97 +334,30 @@ class AppleTVPlus(BaseService): def configure(self) -> None: self.log.info(" + Logging into Apple TV+...") - environment = self.get_environment_config() - if not environment: - raise ValueError("Failed to get AppleTV+ WEB TV App Environment Configuration...") - self.session.headers.update({ - "User-Agent": self.config["user_agent"], - "Authorization": f"Bearer {environment['MEDIA_API']['token']}", - "media-user-token": self.session.cookies.get_dict()["media-user-token"], - "x-apple-music-user-token": self.session.cookies.get_dict()["media-user-token"] - }) - def get_environment_config(self): - """Loads environment config data from WEB App's tag.""" - res = self.session.get("https://tv.apple.com").text - env = search(pattern = r'web-tv-app/config/environment"[\s\S]*?content="([^"]+)', string = res) - if not env: + req = self.session.get("https://tv.apple.com") + data = req.text + + data = search( + pattern=r'web-tv-app/config/environment"[\s\S]*?content="([^"]+)', + string=data, + ) + + if data: + data = loads(unquote(data[1])) + + else: raise ValueError( "Failed to get AppleTV+ WEB TV App Environment Configuration..." ) - return loads(unquote(env[1])) - def scan(self, start: int, length: int) -> list: - - # poetry run vt dl -al en -sl en --selected --proxy http://192.168.0.99:9766 --keys -q 2160 -v H265 ATVP - # poetry run vt dl -al en -sl en --selected --proxy http://192.168.0.99:9766 --keys -q 2160 -v H265 -r DV ATVP - - urls = [] - params = self.config["device"] - params["utscf"] = "OjAAAAEAAAAAAAAAEAAAACMA" - params["nextToken"] = str(start) - - r = None - try: - r = self.session.get( - url=self.config["endpoints"]["homecanvas"], - params=params - ) - except requests.HTTPError as e: - if e.response.status_code != 404: - raise - - if not r: - raise self.log.exit(f" - Canvas endpoint errored out") - try: - shelves = r.json()["data"]["canvas"]["shelves"] - except json.JSONDecodeError: - raise ValueError(f"Failed to load title manifest: {r.text}") - - # TODO - Add check userisentitledtoplay before appending url - for shelf in shelves: - items = shelf["items"] - for item in items: - urls.append(item["url"]) - - url_regex = re.compile(r"^(?:https?://tv\.apple\.com(?:/[a-z]{2})?/(?Pmovie|show|episode)/[a-z0-9-]+/)?(?Pumc\.cmc\.[a-z0-9]+)") - - for url in urls: - match = url_regex.match(url) - - if match: - # Extract the title type and ID - title_type = match.group("type") + "s" # None if not present - title_id = match.group("id") - - else: - continue - - r = None - try: - r = self.session.get( - url=self.config["endpoints"]["title"].format(type=title_type, id=title_id), - params=self.config["device"] - ) - except requests.HTTPError as e: - if e.response.status_code != 404: - raise - if not r: - raise self.log.exit(f" - Title ID {self.title!r} could not be found.") - try: - shelves = r.json()["data"]["canvas"]["shelves"] - except json.JSONDecodeError: - raise ValueError(f"Failed to load title manifest: {r.text}") - - for shelf in shelves: - if "uts.col.ContentRelated" in shelf["id"]: - items = shelf["items"] - for item in items: - if item["url"] not in urls: - # TODO - Add check userisentitledtoplay before appending url - urls.append(item["url"]) - - if len(urls) >= length: - break - - return urls \ No newline at end of file + self.session.headers.update( + { + "Authorization": f"Bearer {data['MEDIA_API']['token']}", + "Media-User-Token": self.session.cookies.get_dict()["media-user-token"], + "User-Agent": self.config["user_agent"], + "X-Apple-Music-User-Token": self.session.cookies.get_dict()[ + "media-user-token" + ], + } + ) diff --git a/vinetrimmer/services/appletvplus2.py b/vinetrimmer/services/appletvplus2.py deleted file mode 100644 index 162125b..0000000 --- a/vinetrimmer/services/appletvplus2.py +++ /dev/null @@ -1,318 +0,0 @@ -import base64 -import json -import re -from datetime import datetime -from urllib.parse import unquote - -import click -import m3u8 -import requests - -from vinetrimmer.objects import AudioTrack, TextTrack, Title, Tracks, VideoTrack -from vinetrimmer.services.BaseService import BaseService -from vinetrimmer.utils.collections import as_list -from vinetrimmer.vendor.pymp4.parser import Box - - -class AppleTVPlus(BaseService): - """ - Service code for Apple's TV Plus streaming service (https://tv.apple.com). - - \b - WIP: decrypt and removal of bumper/dub cards - - \b - Authorization: Cookies - Security: UHD@L1 FHD@L1 HD@L3 - """ - - ALIASES = ["ATVP", "appletvplus", "appletv+"] - TITLE_RE = r"^(?:https?://tv\.apple\.com(?:/[a-z]{2})?/(?:movie|show|episode)/[a-z0-9-]+/)?(?Pumc\.cmc\.[a-z0-9]+)" # noqa: E501 - - VIDEO_CODEC_MAP = { - "H264": ["avc"], - "H265": ["hvc", "hev", "dvh"] - } - AUDIO_CODEC_MAP = { - "AAC": ["HE", "stereo"], - "AC3": ["ac3"], - "EC3": ["ec3", "atmos"] - } - - @staticmethod - @click.command(name="AppleTVPlus", short_help="https://tv.apple.com") - @click.argument("title", type=str, required=False) - @click.option("-svcId", "--serviceid", type=str, default="tvs.vds.4055", help="Define ServiceID if needed.") - @click.option("-sf", "--storefront", type=int, default="143450", help="Define storefront int if needed.") - @click.pass_context - def cli(ctx, **kwargs): - return AppleTVPlus(ctx, **kwargs) - - def __init__(self, ctx, title, serviceid: bool, storefront): - super().__init__(ctx) - self.parse_title(ctx, title) - self.serviceid = serviceid - self.storefront = storefront - - self.vcodec = ctx.parent.params["vcodec"] - self.acodec = ctx.parent.params["acodec"] - self.alang = ctx.parent.params["alang"] - self.subs_only = ctx.parent.params["subs_only"] - - self.extra_server_parameters = None - - self.configure() - - def get_titles(self): - r = None - for i in range(2): - try: - self.params = { - 'utsk': '6e3013c6d6fae3c2::::::9318c17fb39d6b9c', - 'caller': 'web', - 'sf': self.storefront, - 'v': '46', - 'pfm': 'appletv', - 'mfr': 'Apple', - 'locale': 'en-US', - 'l': 'en', - 'ctx_brand': 'tvs.sbd.4000', - 'count': '100', - 'skip': '0', - 'svcId': 'tvs.vds.4105' - } - r = self.session.get( - url=self.config["endpoints"]["title"].format(type={0: "shows", 1: "movies"}[i], id=self.title), - params=self.params - ) - except requests.HTTPError as e: - if e.response.status_code != 404: - raise - else: - if r.ok: - break - if not r: - raise self.log.exit(f" - Title ID {self.title!r} could not be found.") - try: - title_information = r.json()["data"]["content"] - except json.JSONDecodeError: - raise ValueError(f"Failed to load title manifest: {r.text}") - - if title_information["type"] == "Movie": - return Title( - id_=self.title, - type_=Title.Types.MOVIE, - name=title_information["title"], - #year=datetime.utcfromtimestamp(title_information["releaseDate"] / 1000).year, - original_lang=title_information["originalSpokenLanguages"][0]["locale"], - source=self.ALIASES[0], - service_data=title_information - ) - else: - r = self.session.get( - url=self.config["endpoints"]["tv_episodes"].format(id=self.title), - params=self.params - ) - try: - episodes = r.json()["data"]["episodes"] - except json.JSONDecodeError: - raise ValueError(f"Failed to load episodes list: {r.text}") - - return [Title( - id_=self.title, - type_=Title.Types.TV, - name=episode["showTitle"], - season=episode["seasonNumber"], - episode=episode["episodeNumber"], - episode_name=episode.get("title"), - original_lang=title_information["originalSpokenLanguages"][0]["locale"], - source=self.ALIASES[0], - service_data=episode - ) for episode in episodes] - - def get_tracks(self, title): - self.params = { - 'utsk': '6e3013c6d6fae3c2::::::9318c17fb39d6b9c', - 'caller': 'web', - 'sf': self.storefront, - 'v': '46', - 'pfm': 'appletv', - 'mfr': 'Apple', - 'locale': 'en-US', - 'l': 'en', - 'ctx_brand': 'tvs.sbd.4000', - 'count': '100', - 'skip': '0', - 'svcId': 'tvs.vds.4105' - } - r = self.session.get( - url=self.config["endpoints"]["manifest"].format(id=title.service_data["id"]), - params=self.params - ) - try: - stream_data = r.json() - except json.JSONDecodeError: - raise ValueError(f"Failed to load stream data: {r.text}") - stream_data = stream_data["data"]["content"]["playables"][0] - - if not stream_data["isEntitledToPlay"]: - raise self.log.exit(" - User is not entitled to play this title") - - self.extra_server_parameters = stream_data["assets"]["fpsKeyServerQueryParameters"] - print(stream_data["assets"]["hlsUrl"]) - r = requests.get(url=stream_data["assets"]["hlsUrl"], headers={'User-Agent': 'AppleTV6,2/11.1'}) - res = r.text - - tracks = Tracks.from_m3u8( - master=m3u8.loads(res, r.url), - source=self.ALIASES[0] - ) - - for track in tracks: - track.extra = {"manifest": track.extra} - - quality = None - for line in res.splitlines(): - if line.startswith("#--"): - quality = {"SD": 480, "HD720": 720, "HD": 1080, "UHD": 2160}.get(line.split()[2]) - elif not line.startswith("#"): - track = next((x for x in tracks.videos if x.extra["manifest"].uri == line), None) - if track: - track.extra["quality"] = quality - - for track in tracks: - track_data = track.extra["manifest"] - #if isinstance(track, VideoTrack) and not tracks.subtitles: - # track.needs_ccextractor_first = True - if isinstance(track, VideoTrack): - track.encrypted = True - if isinstance(track, AudioTrack): - track.encrypted = True - bitrate = re.search(r"&g=(\d+?)&", track_data.uri) - if not bitrate: - bitrate = re.search(r"_gr(\d+)_", track_data.uri) # new - if bitrate: - track.bitrate = int(bitrate[1][-3::]) * 1000 # e.g. 128->128,000, 2448->448,000 - else: - raise ValueError(f"Unable to get a bitrate value for Track {track.id}") - track.codec = track.codec.replace("_vod", "") - if isinstance(track, TextTrack): - track.codec = "vtt" - - tracks.videos = [x for x in tracks.videos if (x.codec or "")[:3] in self.VIDEO_CODEC_MAP[self.vcodec]] - - if self.acodec: - tracks.audios = [ - x for x in tracks.audios if (x.codec or "").split("-")[0] in self.AUDIO_CODEC_MAP[self.acodec] - ] - - tracks.subtitles = [ - x for x in tracks.subtitles - if (x.language in self.alang or (x.is_original_lang and "orig" in self.alang) or "all" in self.alang) - or self.subs_only - or not x.sdh - ] - - try: - return Tracks([ - # multiple CDNs, only want one - x for x in tracks - if any( - cdn in as_list(x.url)[0].split("?")[1].split("&") for cdn in ["cdn=ak", "cdn=vod-ak-aoc.tv.apple.com"] - ) - ]) - except: - return Tracks([ - # multiple CDNs, only want one - x for x in tracks - #if any( - # cdn in as_list(x.url)[0].split("?")[1].split("&") for cdn in ["cdn=ak", "cdn=vod-ak-aoc.tv.apple.com"] - #) - ]) - - def get_chapters(self, title): - return [] - - def certificate(self, **_): - return None # will use common privacy cert - - def license(self, challenge, track, **_): - try: - res = self.session.post( - url=self.config["endpoints"]["license"], - json={ - 'streaming-request': { - 'version': 1, - 'streaming-keys': [ - { - "challenge": base64.b64encode(challenge.encode('utf-8')).decode('utf-8'), - "key-system": "com.microsoft.playready", - "uri": f"data:text/plain;charset=UTF-16;base64,{track.pssh}", - "id": 1, - "lease-action": 'start', - "adamId": self.extra_server_parameters['adamId'], - "isExternal": True, - 'svcId': self.extra_server_parameters["svcId"] - }, - ], - }, - } - ).json() - except requests.HTTPError as e: - print(e) - if not e.response.text: - raise self.log.exit(" - No license returned!") - raise self.log.exit(f" - Unable to obtain license (error code: {e.response.json()['errorCode']})") - if "license" not in res['streaming-response']['streaming-keys'][0]: - print("Custom license") - try: - res = self.session.post( - url=self.config["endpoints"]["license"], - json={ - 'streaming-request': { - 'version': 1, - 'streaming-keys': [ - { - "challenge": base64.b64encode(challenge.encode('utf-8')).decode('utf-8'), - "key-system": "com.microsoft.playready", - "uri": f"data:text/plain;charset=UTF-16;base64,{track.pssh}", - "id": 1, - "lease-action": 'start', - "adamId": self.extra_server_parameters['adamId'], - "isExternal": True, - "svcId": self.extra_server_parameters["svcId"] - }, - ], - }, - } - ).json() - self.log.debug(res) - except requests.HTTPError as e: - print(e) - if not e.response.text: - raise self.log.exit(" - No license returned!") - raise self.log.exit(f" - Unable to obtain license (error code: {e.response.json()['errorCode']})") - return res['streaming-response']['streaming-keys'][0]["license"] - return res['streaming-response']['streaming-keys'][0]["license"] - - - # Service specific functions - - def configure(self): - environment = self.get_environment_config() - if not environment: - raise ValueError("Failed to get AppleTV+ WEB TV App Environment Configuration...") - self.session.headers.update({ - "User-Agent": self.config["user_agent"], - "Authorization": f"Bearer {environment['MEDIA_API']['token']}", - "media-user-token": self.session.cookies.get_dict()["media-user-token"], - "x-apple-music-user-token": self.session.cookies.get_dict()["media-user-token"] - }) - - def get_environment_config(self): - """Loads environment config data from WEB App's tag.""" - res = self.session.get("https://tv.apple.com").text - env = re.search(r'web-tv-app/config/environment"[\s\S]*?content="([^"]+)', res) - if not env: - return None - return json.loads(unquote(env[1])) diff --git a/vinetrimmer/services/max.py b/vinetrimmer/services/max.py index 5f80c38..5c50ce4 100644 --- a/vinetrimmer/services/max.py +++ b/vinetrimmer/services/max.py @@ -53,6 +53,7 @@ class Max(BaseService): def __init__(self, ctx, title): super().__init__(ctx) + self.quality = ctx.parent.params["quality"] self.title = self.parse_title(ctx, title) # self.movie = movie @@ -69,12 +70,10 @@ class Max(BaseService): # self.auth_grant = None # self.profile_id = None # self.entitlements = None - - - if self.range == 'HDR10' or self.range == 'DV' or self.quality > 1080: - self.log.info(" + Setting VideoCodec to H265 to be able to get 2160p video track") - self.vcodec = "H265" + if ("HDR" in self.range) or (self.range == "DV") or ((self.quality << 1080) if self.quality else False): + self.log.info(" - Setting Video codec to H265 to get UHD") + self.vcodec = "H265" self.configure() def get_titles(self): diff --git a/vinetrimmer/services/netflix.py b/vinetrimmer/services/netflix.py index 7bd0f74..c318bc6 100644 --- a/vinetrimmer/services/netflix.py +++ b/vinetrimmer/services/netflix.py @@ -17,7 +17,7 @@ from vinetrimmer.utils.collections import as_list, flatten from vinetrimmer.utils.MSL import MSL from vinetrimmer.utils.MSL.schemes import KeyExchangeSchemes from vinetrimmer.utils.MSL.schemes.UserAuthentication import UserAuthentication -from pywidevine.device import DeviceTypes +from vinetrimmer.utils.widevine.device import LocalDevice from vinetrimmer.vendor.pymp4.parser import Box from vinetrimmer.utils.gen_esn import chrome_esn_generator @@ -135,7 +135,7 @@ class Netflix(BaseService): service_data=episode ) for episode in episodes] - # TODO: Get original language without making an extra manifest.xml request + # TODO: Get original language without making an extra manifest request self.log.warning("HEVC PROFILES for the first title sometimes FAIL with Validation error so we use H264 HPL as a first trial, if it does not exist, we try H264 MPL") try: manifest = self.get_manifest(titles[0], self.profiles) @@ -177,13 +177,13 @@ class Netflix(BaseService): license_url = manifest["links"]["license"]["href"] - if self.cdm.device.security_level == 3 and self.cdm.device.type == DeviceTypes.ANDROID: + if self.cdm.device.security_level == 3 and self.cdm.device.type == LocalDevice.Types.ANDROID: max_quality = max(x.height for x in manifest_tracks.videos) if profile == "MPL" and max_quality >= 720: manifest_sd = self.get_manifest(title, self.config["profiles"]["video"]["H264"]["BPL"]) license_url_sd = manifest_sd["links"]["license"]["href"] if "SD_LADDER" in manifest_sd["video_tracks"][0]["streams"][0]["tags"]: - # SD manifest.xml is new encode encrypted with different keys that won't work for HD + # SD manifest is new encode encrypted with different keys that won't work for HD continue license_url = license_url_sd if profile == "HPL" and max_quality >= 1080: @@ -383,8 +383,10 @@ class Netflix(BaseService): self.profiles = self.get_profiles() self.log.info("Initializing a Netflix MSL client") # Grab ESN based on CDM from secrets if no ESN argument provided - if self.cdm.device.type == DeviceTypes.CHROME: # ESN GENERATOR FOR CHROME + if (self.cdm.device.type == LocalDevice.Types.CHROME if "common_privacy_cert" in dir(self.cdm) else False): # ESN GENERATOR FOR CHROME self.esn = chrome_esn_generator() + elif "group_certificate" in dir(self.cdm): + self.esn = edge_esn_generator() else: sel.log.info(self.config) esn_map = self.config.get("esn_map", {}) @@ -394,14 +396,14 @@ class Netflix(BaseService): raise self.log.exit(" - No ESN specified") self.log.info(f" + ESN: {self.esn}") scheme = { - DeviceTypes.CHROME: KeyExchangeSchemes.AsymmetricWrapped, - DeviceTypes.ANDROID: KeyExchangeSchemes.Widevine + LocalDevice.Types.CHROME: KeyExchangeSchemes.AsymmetricWrapped, + LocalDevice.Types.ANDROID: KeyExchangeSchemes.Widevine }[self.cdm.device.type] self.log.info(f" + Scheme: {scheme}") self.msl = MSL.handshake( scheme=scheme, session=self.session, - endpoint=self.config["endpoints"]["manifest.xml"], + endpoint=self.config["endpoints"]["manifest"], sender=self.esn, cdm=self.cdm, msl_keys_path=self.get_cache("msl_{id}_{esn}_{scheme}.json".format( @@ -412,7 +414,7 @@ class Netflix(BaseService): ) if not self.session.cookies: raise self.log.exit(" - No cookies provided, cannot log in.") - if self.cdm.device.type == DeviceTypes.CHROME: + if self.cdm.device.type == LocalDevice.Types.CHROME: self.userauthdata = UserAuthentication.NetflixIDCookies( netflixid=self.session.cookies.get_dict()["NetflixId"], securenetflixid=self.session.cookies.get_dict()["SecureNetflixId"] @@ -634,17 +636,17 @@ class Netflix(BaseService): self.log.debug("Profiles:\n\t" + "\n\t".join(profiles)) params = {} - if self.cdm.device.type == DeviceTypes.CHROME: + if (self.cdm.device.type == LocalDevice.Types.CHROME if "common_privacy_cert" in dir(self.cdm) else False): params = { "reqAttempt": 1, "reqPriority": 0, - "reqName": "prefetch/manifest.xml", + "reqName": "prefetch/manifest", "clienttype": "akira", } manifest_data = { 'version': 2, - 'url': '/manifest.xml', + 'url': '/manifest', "id": int(time.time()), "esn": self.esn, 'languages': ['en-US'], @@ -691,7 +693,7 @@ class Netflix(BaseService): _, payload_chunks = self.msl.send_message( - endpoint=self.config["endpoints"]["manifest.xml"], + endpoint=self.config["endpoints"]["manifest"], params=params, application_data=manifest_data, userauthdata=self.userauthdata diff --git a/vinetrimmer/services/peacock.py b/vinetrimmer/services/peacock.py deleted file mode 100644 index c312be2..0000000 --- a/vinetrimmer/services/peacock.py +++ /dev/null @@ -1,421 +0,0 @@ -import base64 -import hashlib -import hmac -import json -import os -import time -from datetime import datetime - -import click -import requests - -from vinetrimmer.objects import Title, Tracks -from vinetrimmer.services.BaseService import BaseService -from vinetrimmer.utils.regex import find - - -class Peacock(BaseService): - """ - Service code for NBC's Peacock streaming service (https://peacocktv.com). - - \b - Authorization: Cookies - Security: UHD@-- FHD@L3, doesn't care about releases. - - \b - Tips: - The library of contents can be viewed without logging in at https://www.peacocktv.com/stream/tv - See the footer for links to movies, news, etc. A US IP is required to view. - """ - - ALIASES = ["PCOK", "peacock"] - #GEOFENCE = ["us"] - TITLE_RE = [ - r"(?:https?://(?:www\.)?peacocktv\.com/watch/asset/|/?)(?Pmovies/[a-z0-9/./-]+/[a-f0-9-]+)", - r"(?:https?://(?:www\.)?peacocktv\.com/watch/asset/|/?)(?Ptv/[a-z0-9-/.]+/\d+)", - r"(?:https?://(?:www\.)?peacocktv\.com/watch/asset/|/?)(?P-/[a-z0-9-/.]+/\d+)", - r"(?:https?://(?:www\.)?peacocktv\.com/stream-tv/)?(?P[a-z0-9-/.]+)", - ] - - @staticmethod - @click.command(name="Peacock", short_help="https://peacocktv.com") - @click.argument("title", type=str, required=False) - @click.option("-m", "--movie", is_flag=True, default=False, help="Title is a movie.") - @click.pass_context - def cli(ctx, **kwargs): - return Peacock(ctx, **kwargs) - - def __init__(self, ctx, title, movie): - super().__init__(ctx) - self.parse_title(ctx, title) - self.movie = movie - - self.profile = ctx.obj.profile - - self.service_config = None - self.hmac_key = None - self.tokens = None - self.license_api = None - self.license_bt = None - self.vcodec = ctx.parent.params["vcodec"] - self.vrange= ctx.parent.params["range_"] - - self.configure() - - def get_titles(self): - # Title is a slug, e.g. `/tv/the-office/4902514835143843112` or just `the-office` - - if "/" not in self.title: - r = self.session.get(self.config["endpoints"]["stream_tv"].format(title_id=self.title)) - self.title = find("/watch/asset(/[^']+)", r.text) - if not self.title: - raise self.log.exit(" - Title ID not found or invalid") - - if not self.title.startswith("/"): - self.title = f"/{self.title}" - - if self.title.startswith("/movies/"): - self.movie = True - - res = self.session.get( - url=self.config["endpoints"]["node"], - params={ - "slug": self.title, - "represent": "(items(items))" - }, - headers={ - "Accept": "*", - "Referer": f"https://www.peacocktv.com/watch/asset{self.title}", - "X-SkyOTT-Device": self.config["client"]["device"], - "X-SkyOTT-Platform": self.config["client"]["platform"], - "X-SkyOTT-Proposition": self.config["client"]["proposition"], - "X-SkyOTT-Provider": self.config["client"]["provider"], - "X-SkyOTT-Territory": self.config["client"]["territory"], - "X-SkyOTT-Language": "en" - } - ).json() - - if self.movie: - return Title( - id_=self.title, - type_=Title.Types.MOVIE, - name=res["attributes"]["title"], - year=res["attributes"]["year"], - source=self.ALIASES[0], - service_data=res, - ) - else: - titles = [] - for season in res["relationships"]["items"]["data"]: - for episode in season["relationships"]["items"]["data"]: - titles.append(episode) - return [Title( - id_=self.title, - type_=Title.Types.TV, - name=res["attributes"]["title"], - year=x["attributes"].get("year"), - season=x["attributes"].get("seasonNumber"), - episode=x["attributes"].get("episodeNumber"), - episode_name=x["attributes"].get("title"), - source=self.ALIASES[0], - service_data=x - ) for x in titles] - - def get_tracks(self, title): - supported_colour_spaces=["SDR"] - - if self.vrange == "HDR10": - self.log.info("Switched dynamic range to HDR10") - supported_colour_spaces=["HDR10"] - if self.vrange == "DV": - self.log.info("Switched dynamic range to DV") - supported_colour_spaces=["DolbyVision"] - content_id = title.service_data["attributes"]["formats"]["HD"]["contentId"] - variant_id = title.service_data["attributes"]["providerVariantId"] - - sky_headers = { - # order of these matter! - "X-SkyOTT-Agent": ".".join([ - self.config["client"]["proposition"].lower(), - self.config["client"]["device"].lower(), - self.config["client"]["platform"].lower() - ]), - "X-SkyOTT-PinOverride": "false", - "X-SkyOTT-Provider": self.config["client"]["provider"], - "X-SkyOTT-Territory": self.config["client"]["territory"], - "X-SkyOTT-UserToken": self.tokens["userToken"] - } - - body = json.dumps({ - "device": { - # maybe get these from the config endpoint? - "capabilities": [ - { - "protection": "PLAYREADY", - "container": "ISOBMFF", - "transport": "DASH", - "acodec": "AAC", - "vcodec": "H265" if self.vcodec == "H265" else "H264", - }, - { - "protection": "NONE", - "container": "ISOBMFF", - "transport": "DASH", - "acodec": "AAC", - "vcodec": "H265" if self.vcodec == "H265" else "H264", - } - ], - "maxVideoFormat": "UHD" if self.vcodec == "H265" else "HD", - "supportedColourSpaces": supported_colour_spaces, - "model": self.config["client"]["platform"], - "hdcpEnabled": "true" - }, - "client": { - "thirdParties": ["FREEWHEEL", "YOSPACE"] # CONVIVA - }, - "contentId": content_id, - "providerVariantId": variant_id, - "parentalControlPin": "null" - }, separators=(",", ":")) - - manifest = self.session.post( - url=self.config["endpoints"]["vod"], - data=body, - headers=dict(**sky_headers, **{ - "Accept": "application/vnd.playvod.v1+json", - "Content-Type": "application/vnd.playvod.v1+json", - "X-Sky-Signature": self.create_signature_header( - method="POST", - path="/video/playouts/vod", - sky_headers=sky_headers, - body=body, - timestamp=int(time.time()) - ) - }) - ).json() - if "errorCode" in manifest: - raise self.log.exit(f" - An error occurred: {manifest['description']} [{manifest['errorCode']}]") - - self.license_api = manifest["protection"]["licenceAcquisitionUrl"] - self.license_bt = manifest["protection"]["licenceToken"] - - tracks = Tracks.from_mpd( - url=manifest["asset"]["endpoints"][0]["url"], - session=self.session, - source=self.ALIASES[0] - ) - - if supported_colour_spaces == ["HDR10"]: - for track in tracks.videos: - track.hdr10 = True if supported_colour_spaces == ["HDR10"] else False - if supported_colour_spaces == ["DolbyVision"]: - for track in tracks.videos: - track.dolbyvison = True if supported_colour_spaces == ["DV"] else False - - for track in tracks: - track.needs_proxy = False - - for track in tracks.audios: - if track.language.territory == "AD": - # This is supposed to be Audio Description, not Andorra - track.language.territory = None - - return tracks - - def get_chapters(self, title): - return [] - - def license(self, challenge, **_): - request = self.session.post( - url=self.license_api, - headers={ - "Accept": "*", - "X-Sky-Signature": self.create_signature_header( - method="POST", - path="/" + self.license_api.split("://", 2)[1].split("/", 1)[1], - sky_headers={}, - body="", - timestamp=int(time.time()) - ) - }, - data=challenge # expects bytes - ) - return request.text - # Service specific functions - - def configure(self): - self.session.headers.update({"Origin": "https://www.peacocktv.com"}) - self.log.info("Getting Peacock Client configuration") - if self.config["client"]["platform"] != "PC": - self.service_config = self.session.get( - url=self.config["endpoints"]["config"].format( - territory=self.config["client"]["territory"], - provider=self.config["client"]["provider"], - proposition=self.config["client"]["proposition"], - device=self.config["client"]["platform"], - version=self.config["client"]["config_version"], - ) - ).json() - self.hmac_key = bytes(self.config["security"]["signature_hmac_key_v4"], "utf-8") - self.log.info("Getting Authorization Tokens") - self.tokens = self.get_tokens() - self.log.info("Verifying Authorization Tokens") - if not self.verify_tokens(): - raise self.log.exit(" - Failed! Cookies might be outdated.") - - @staticmethod - def calculate_sky_header_md5(headers): - if len(headers.items()) > 0: - headers_str = "\n".join(f"{x[0].lower()}: {x[1]}" for x in headers.items()) + "\n" - else: - headers_str = "{}" - return str(hashlib.md5(headers_str.encode()).hexdigest()) - - @staticmethod - def calculate_body_md5(body): - return str(hashlib.md5(body.encode()).hexdigest()) - - def calculate_signature(self, msg): - digest = hmac.new(self.hmac_key, bytes(msg, "utf-8"), hashlib.sha1).digest() - return str(base64.b64encode(digest), "utf-8") - - def create_signature_header(self, method, path, sky_headers, body, timestamp): - data = "\n".join([ - method.upper(), - path, - "", # important! - self.config["client"]["client_sdk"], - "1.0", - self.calculate_sky_header_md5(sky_headers), - str(timestamp), - self.calculate_body_md5(body) - ]) + "\n" - - signature_hmac = self.calculate_signature(data) - - return self.config["security"]["signature_format"].format( - client=self.config["client"]["client_sdk"], - signature=signature_hmac, - timestamp=timestamp - ) - - def get_tokens(self): - # Try to get cached tokens - tokens_cache_path = self.get_cache("tokens_{profile}_{id}.json".format( - profile=self.profile, - id=self.config["client"]["id"] - )) - if os.path.isfile(tokens_cache_path): - with open(tokens_cache_path, encoding="utf-8") as fd: - tokens = json.load(fd) - tokens_expiration = tokens.get("tokenExpiryTime", None) - if tokens_expiration and datetime.strptime(tokens_expiration, "%Y-%m-%dT%H:%M:%S.%fZ") > datetime.now(): - return tokens - - # Get all SkyOTT headers - sky_headers = { - # Order of these matters! - "X-SkyOTT-Agent": ".".join([ - self.config["client"]["proposition"], - self.config["client"]["device"], - self.config["client"]["platform"] - ]).lower(), - "X-SkyOTT-Device": self.config["client"]["device"], - "X-SkyOTT-Platform": self.config["client"]["platform"], - "X-SkyOTT-Proposition": self.config["client"]["proposition"], - "X-SkyOTT-Provider": self.config["client"]["provider"], - "X-SkyOTT-Territory": self.config["client"]["territory"] - } - - print(self.session.cookies) - - try: - # Call personas endpoint to get the accounts personaId - personas = self.session.get( - url=self.config["endpoints"]["personas"], - headers=dict(**sky_headers, **{ - "Accept": "application/vnd.persona.v1+json", - "Content-Type": "application/vnd.persona.v1+json", - "X-SkyOTT-TokenType": self.config["client"]["auth_scheme"] - }) - ).json() - except requests.HTTPError as e: - error = e.response.json() - if "message" in error and "code" in error: - error = f"{error['message']} [{error['code']}]" - if "bad credentials" in error.lower(): - error += ". Cookies may be expired or invalid." - raise self.log.exit(f" - Unable to get persona ID: {error}") - raise self.log.exit(f" - HTTP Error {e.response.status_code}: {e.response.reason}") - persona = personas["personas"][0]["personaId"] - - # Craft the body data that will be sent to the tokens endpoint, being minified and order matters! - body = json.dumps({ - "auth": { - "authScheme": self.config["client"]["auth_scheme"], - "authIssuer": self.config["client"]["auth_issuer"], - "provider": self.config["client"]["provider"], - "providerTerritory": self.config["client"]["territory"], - "proposition": self.config["client"]["proposition"], - "personaId": persona - }, - "device": { - "type": self.config["client"]["device"], - "platform": self.config["client"]["platform"], - "id": self.config["client"]["id"], - "drmDeviceId": self.config["client"]["drm_device_id"] - } - }, separators=(",", ":")) - - # Get the tokens - tokens = self.session.post( - url=self.config["endpoints"]["tokens"], - headers=dict(**sky_headers, **{ - "Accept": "application/vnd.tokens.v1+json", - "Content-Type": "application/vnd.tokens.v1+json", - "X-Sky-Signature": self.create_signature_header( - method="POST", - path="/auth/tokens", - sky_headers=sky_headers, - body=body, - timestamp=int(time.time()) - ) - }), - data=body - ).json() - - os.makedirs(os.path.dirname(tokens_cache_path), exist_ok=True) - with open(tokens_cache_path, "w", encoding="utf-8") as fd: - json.dump(tokens, fd) - - return tokens - - def verify_tokens(self): - """Verify the tokens by calling the /auth/users/me endpoint and seeing if it works""" - sky_headers = { - # order of these matter! - "X-SkyOTT-Device": self.config["client"]["device"], - "X-SkyOTT-Platform": self.config["client"]["platform"], - "X-SkyOTT-Proposition": self.config["client"]["proposition"], - "X-SkyOTT-Provider": self.config["client"]["provider"], - "X-SkyOTT-Territory": self.config["client"]["territory"], - "X-SkyOTT-UserToken": self.tokens["userToken"] - } - try: - self.session.get( - url=self.config["endpoints"]["me"], - headers=dict(**sky_headers, **{ - "Accept": "application/vnd.userinfo.v2+json", - "Content-Type": "application/vnd.userinfo.v2+json", - "X-Sky-Signature": self.create_signature_header( - method="GET", - path="/auth/users/me", - sky_headers=sky_headers, - body="", - timestamp=int(time.time()) - ) - }) - ) - except requests.HTTPError: - return False - else: - return True diff --git a/vinetrimmer/utils/MSL/__init__.py b/vinetrimmer/utils/MSL/__init__.py index 2eee0e7..ea3f3c3 100644 --- a/vinetrimmer/utils/MSL/__init__.py +++ b/vinetrimmer/utils/MSL/__init__.py @@ -138,7 +138,7 @@ class MSL: key_data = key_response_data["keydata"] if scheme == KeyExchangeSchemes.Widevine: - if "Remote" in cdm.device.__class__.__name__: + try: msl_keys.encryption, msl_keys.sign = cdm.device.exchange( cdm.sessions[msl_keys.cdm_session], license_res=key_data["cdmkeyresponse"], @@ -146,7 +146,7 @@ class MSL: hmac_key_id=base64.b64decode(key_data["hmackeyid"]) ) cdm.parse_license(msl_keys.cdm_session, key_data["cdmkeyresponse"]) - else: + except: cdm.parse_license(msl_keys.cdm_session, key_data["cdmkeyresponse"]) keys = cdm.get_keys(msl_keys.cdm_session) msl_keys.encryption = MSL.get_widevine_key( diff --git a/vinetrimmer/utils/__init__.py b/vinetrimmer/utils/__init__.py index 2de2c35..13098d5 100644 --- a/vinetrimmer/utils/__init__.py +++ b/vinetrimmer/utils/__init__.py @@ -1,6 +1,8 @@ from langcodes import Language, closest_match from vinetrimmer.constants import LANGUAGE_MAX_DISTANCE +from vinetrimmer.utils.widevine.cdm import Cdm # noqa: F401 +from vinetrimmer.utils.widevine.protos.widevine_pb2 import WidevineCencHeader # noqa: F401 from vinetrimmer.vendor.pymp4.parser import Box diff --git a/vinetrimmer/utils/io.py b/vinetrimmer/utils/io.py index 855703c..82a3acc 100644 --- a/vinetrimmer/utils/io.py +++ b/vinetrimmer/utils/io.py @@ -1,8 +1,6 @@ import asyncio import contextlib -import logging import os -from pathlib import Path import re import shutil import subprocess @@ -17,285 +15,221 @@ from vinetrimmer.utils.collections import as_list def load_yaml(path): - if not os.path.isfile(path): - return {} - with open(path) as fd: - return yaml.safe_load(fd) + if not os.path.isfile(path): + return {} + with open(path) as fd: + return yaml.safe_load(fd) _ip_info = None def get_ip_info(session=None, fresh=False): - """Use extreme-ip-lookup.com to get IP location information.""" - global _ip_info + """Use extreme-ip-lookup.com to get IP location information.""" + global _ip_info - if fresh or not _ip_info: - # alternatives: http://www.geoplugin.net/json.gp, http://ip-api.com/json/, https://extreme-ip-lookup.com/json - # _ip_info = (session or httpx).get("https://ip-api.com/json/").json() - _ip_info = (session or httpx).get("http://ip-api.com/json/").json() + if fresh or not _ip_info: + # alternatives: http://www.geoplugin.net/json.gp, http://ip-api.com/json/, https://extreme-ip-lookup.com/json + _ip_info = (session or httpx).get("http://ip-api.com/json/").json() - return _ip_info + return _ip_info @contextlib.asynccontextmanager async def start_pproxy(host, port, username, password): - rerouted_proxy = "http://localhost:8081" - server = pproxy.Server(rerouted_proxy) - remote = pproxy.Connection(f"http+ssl://{host}:{port}#{username}:{password}") - handler = await server.start_server(dict(rserver=[remote])) - try: - yield rerouted_proxy - finally: - handler.close() - await handler.wait_closed() + rerouted_proxy = "http://localhost:8081" + server = pproxy.Server(rerouted_proxy) + remote = pproxy.Connection(f"http+ssl://{host}:{port}#{username}:{password}") + handler = await server.start_server(dict(rserver=[remote])) + try: + yield rerouted_proxy + finally: + handler.close() + await handler.wait_closed() def download_range(url, count, start=0, proxy=None): - """Download n bytes without using the Range header due to support issues.""" - # TODO: Can this be done with Aria2c? - executable = shutil.which("curl") - if not executable: - raise EnvironmentError("Track needs curl to download a chunk of data but wasn't found...") + """Download n bytes without using the Range header due to support issues.""" + # TODO: Can this be done with Aria2c? + executable = shutil.which("curl") + if not executable: + raise EnvironmentError("Track needs curl to download a chunk of data but wasn't found...") - arguments = [ - executable, - "-s", # use -s instead of --no-progress-meter due to version requirements - "-L", # follow redirects, e.g. http->https - "--proxy-insecure", # disable SSL verification of proxy - "--output", "-", # output to stdout - "--url", url - ] - if proxy: - arguments.extend(["--proxy", proxy]) + arguments = [ + executable, + "-s", # use -s instead of --no-progress-meter due to version requirements + "-L", # follow redirects, e.g. http->https + "--proxy-insecure", # disable SSL verification of proxy + "--output", "-", # output to stdout + "--url", url + ] + if proxy: + arguments.extend(["--proxy", proxy]) - curl = subprocess.Popen( - arguments, - stdout=subprocess.PIPE, - stderr=open(os.devnull, "wb"), - shell=False - ) - buffer = b'' - location = -1 - while len(buffer) < count: - stdout = curl.stdout - data = b'' - if stdout: - data = stdout.read(1) - if len(data) > 0: - location += len(data) - if location >= start: - buffer += data - else: - if curl.poll() is not None: - break - curl.kill() # stop downloading - return buffer + curl = subprocess.Popen( + arguments, + stdout=subprocess.PIPE, + stderr=open(os.devnull, "wb"), + shell=False + ) + buffer = b'' + location = -1 + while len(buffer) < count: + stdout = curl.stdout + data = b'' + if stdout: + data = stdout.read(1) + if len(data) > 0: + location += len(data) + if location >= start: + buffer += data + else: + if curl.poll() is not None: + break + curl.kill() # stop downloading + return buffer async def aria2c(uri, out, headers=None, proxy=None): - """ - Downloads file(s) using Aria2(c). + """ + Downloads file(s) using Aria2(c). - Parameters: - uri: URL to download. If uri is a list of urls, they will be downloaded and - concatenated into one file. - out: The output file path to save to. - headers: Headers to apply on aria2c. - proxy: Proxy to apply on aria2c. - """ - executable = shutil.which("aria2c") or shutil.which("aria2") - if not executable: - raise EnvironmentError("Aria2c executable not found...") + Parameters: + uri: URL to download. If uri is a list of urls, they will be downloaded and + concatenated into one file. + out: The output file path to save to. + headers: Headers to apply on aria2c. + proxy: Proxy to apply on aria2c. + """ + executable = shutil.which("aria2c") or shutil.which("aria2") + if not executable: + raise EnvironmentError("Aria2c executable not found...") - arguments = [ - executable, - "-c", # Continue downloading a partially downloaded file - "--remote-time", # Retrieve timestamp of the remote file from the and apply if available - "-o", os.path.basename(out), # The file name of the downloaded file, relative to -d - "-x", "16", # The maximum number of connections to one server for each download - "-j", "16", # The maximum number of parallel downloads for every static (HTTP/FTP) URL - "-s", "16", # Download a file using N connections. - "--allow-overwrite=true", - "--auto-file-renaming=false", - "--retry-wait", "5", # Set the seconds to wait between retries. - "--max-tries", "15", - "--max-file-not-found", "15", - "--summary-interval", "0", - "--file-allocation", "none" if sys.platform == "win32" else "falloc", - "--console-log-level", "warn", - "--download-result", "hide" - ] + arguments = [ + executable, + "-c", # Continue downloading a partially downloaded file + "--remote-time", # Retrieve timestamp of the remote file from the and apply if available + "-o", os.path.basename(out), # The file name of the downloaded file, relative to -d + "-x", "16", # The maximum number of connections to one server for each download + "-j", "16", # The maximum number of parallel downloads for every static (HTTP/FTP) URL + "-s", "16", # Download a file using N connections. + "--allow-overwrite=true", + "--auto-file-renaming=false", + "--retry-wait", "5", # Set the seconds to wait between retries. + "--max-tries", "15", + "--max-file-not-found", "15", + "--summary-interval", "0", + "--file-allocation", "none" if sys.platform == "win32" else "falloc", + "--console-log-level", "warn", + "--download-result", "hide" + ] - for option, value in config.config.aria2c.items(): - arguments.append(f"--{option.replace('_', '-')}={value}") + for option, value in config.config.aria2c.items(): + arguments.append(f"--{option.replace('_', '-')}={value}") - for header, value in (headers or {}).items(): - if header.lower() == "accept-encoding": - # we cannot set an allowed encoding, or it will return compressed - # and the code is not set up to uncompress the data - continue - arguments.extend(["--header", f"{header}: {value}"]) + for header, value in (headers or {}).items(): + if header.lower() == "accept-encoding": + # we cannot set an allowed encoding, or it will return compressed + # and the code is not set up to uncompress the data + continue + arguments.extend(["--header", f"{header}: {value}"]) - segmented = isinstance(uri, list) - segments_dir = f"{out}_segments" + segmented = isinstance(uri, list) + segments_dir = f"{out}_segments" - if segmented: - uri = "\n".join([ - f"{url}\n" - f"\tdir={segments_dir}\n" - f"\tout={i:08}.mp4" - for i, url in enumerate(uri) - ]) + if segmented: + uri = "\n".join([ + f"{url}\n" + f"\tdir={segments_dir}\n" + f"\tout={i:08}.mp4" + for i, url in enumerate(uri) + ]) - if proxy: - arguments.append("--all-proxy") - if proxy.lower().startswith("https://"): - auth, hostname = proxy[8:].split("@") - async with start_pproxy(*hostname.split(":"), *auth.split(":")) as pproxy_: - arguments.extend([pproxy_, "-d"]) - if segmented: - arguments.extend([segments_dir, "-i-"]) - proc = await asyncio.create_subprocess_exec(*arguments, stdin=subprocess.PIPE) - await proc.communicate(as_list(uri)[0].encode("utf-8")) - else: - arguments.extend([os.path.dirname(out), uri]) - proc = await asyncio.create_subprocess_exec(*arguments) - await proc.communicate() - else: - arguments.append(proxy) + if proxy: + arguments.append("--all-proxy") + if proxy.lower().startswith("https://"): + auth, hostname = proxy[8:].split("@") + async with start_pproxy(*hostname.split(":"), *auth.split(":")) as pproxy_: + arguments.extend([pproxy_, "-d"]) + if segmented: + arguments.extend([segments_dir, "-i-"]) + proc = await asyncio.create_subprocess_exec(*arguments, stdin=subprocess.PIPE) + await proc.communicate(as_list(uri)[0].encode("utf-8")) + else: + arguments.extend([os.path.dirname(out), uri]) + proc = await asyncio.create_subprocess_exec(*arguments) + await proc.communicate() + else: + arguments.append(proxy) - try: - if segmented: - subprocess.run( - arguments + ["-d", segments_dir, "-i-"], - input=as_list(uri)[0], - encoding="utf-8", - check=True - ) - else: - subprocess.run( - arguments + ["-d", os.path.dirname(out), uri], - check=True - ) - except subprocess.CalledProcessError: - raise ValueError("Aria2c failed too many times, aborting") + try: + if segmented: + subprocess.run( + arguments + ["-d", segments_dir, "-i-"], + input=as_list(uri)[0], + encoding="utf-8", + check=True + ) + else: + subprocess.run( + arguments + ["-d", os.path.dirname(out), uri], + check=True + ) + except subprocess.CalledProcessError: + raise ValueError("Aria2c failed too many times, aborting") - if segmented: - # merge the segments together - with open(out, "wb") as ofd: - for file in sorted(os.listdir(segments_dir)): - file = os.path.join(segments_dir, file) - with open(file, "rb") as ifd: - data = ifd.read() - # Apple TV+ needs this done to fix audio decryption - data = re.sub(b"(tfhd\x00\x02\x00\x1a\x00\x00\x00\x01\x00\x00\x00)\x02", b"\\g<1>\x01", data) - ofd.write(data) - os.unlink(file) - os.rmdir(segments_dir) + if segmented: + # merge the segments together + with open(out, "wb") as ofd: + for file in sorted(os.listdir(segments_dir)): + file = os.path.join(segments_dir, file) + with open(file, "rb") as ifd: + data = ifd.read() + # Apple TV+ needs this done to fix audio decryption + data = re.sub(b"(tfhd\x00\x02\x00\x1a\x00\x00\x00\x01\x00\x00\x00)\x02", b"\\g<1>\x01", data) + ofd.write(data) + os.unlink(file) + os.rmdir(segments_dir) - print() + print() async def saldl(uri, out, headers=None, proxy=None): - if headers: - headers.update({k: v for k, v in headers.items() if k.lower() != "accept-encoding"}) + if headers: + headers.update({k: v for k, v in headers.items() if k.lower() != "accept-encoding"}) - executable = shutil.which("saldl") or shutil.which("saldl-win64") or shutil.which("saldl-win32") - if not executable: - raise EnvironmentError("Saldl executable not found...") + executable = shutil.which("saldl") or shutil.which("saldl-win64") or shutil.which("saldl-win32") + if not executable: + raise EnvironmentError("Saldl executable not found...") - arguments = [ - executable, - # "--no-status", - "--skip-TLS-verification", - "--resume", - "--merge-in-order", - "-c8", - "--auto-size", "1", - "-D", os.path.dirname(out), - "-o", os.path.basename(out), - ] + arguments = [ + executable, + # "--no-status", + "--skip-TLS-verification", + "--resume", + "--merge-in-order", + "-c8", + "--auto-size", "1", + "-D", os.path.dirname(out), + "-o", os.path.basename(out), + ] - if headers: - arguments.extend([ - "--custom-headers", - "\r\n".join([f"{k}: {v}" for k, v in headers.items()]) - ]) + if headers: + arguments.extend([ + "--custom-headers", + "\r\n".join([f"{k}: {v}" for k, v in headers.items()]) + ]) - if proxy: - arguments.extend(["--proxy", proxy]) + if proxy: + arguments.extend(["--proxy", proxy]) - if isinstance(uri, list): - raise ValueError("Saldl code does not yet support multiple uri (e.g. segmented) downloads.") - arguments.append(uri) + if isinstance(uri, list): + raise ValueError("Saldl code does not yet support multiple uri (e.g. segmented) downloads.") + arguments.append(uri) - try: - subprocess.run(arguments, check=True) - except subprocess.CalledProcessError: - raise ValueError("Saldl failed too many times, aborting") + try: + subprocess.run(arguments, check=True) + except subprocess.CalledProcessError: + raise ValueError("Saldl failed too many times, aborting") - print() - - -async def m3u8dl(uri: str, out: str, track): - executable = shutil.which("N_m3u8DL-RE") or shutil.which("m3u8DL") - if not executable: - raise EnvironmentError("N_m3u8DL-RE executable not found...") - - ffmpeg_binary = shutil.which("ffmpeg") - - arguments = [ - executable, - uri, - "--save-dir", os.path.dirname(out), - "--tmp-dir", os.path.dirname(out), - "--save-name", os.path.basename(out).replace(".mp4", ""), - "--write-meta-json", "False", - "--log-level", "ERROR", - "--thread-count", "96", - "--download-retry-count", "8", - "--ffmpeg-binary-path", ffmpeg_binary, - "--binary-merge", - "--decryption-engine", "SHAKA_PACKAGER", - "--http-request-timeout", "8", - "--live-real-time-merge" - ] - - if track.__class__.__name__ == "VideoTrack": - if track.height: - arguments.extend([ - "-sv", f"res='{track.height}*':codec='{track.codec}':for=best" - ]) - else: - arguments.extend([ - "-sv", "best" - ]) - - arguments.extend([ - "-da", "all", - "-ds", "all", - ]) - elif track.__class__.__name__ == "AudioTrack": - if track.language: - arguments.extend([ - "-sa", f"lang='{track.language}':for=best" - ]) - else: - arguments.extend([ - "-sa", "best" - ]) - - arguments.extend([ - "-dv", "all", - "-ds", "all", - "-M", "format=mp4:muxer=ffmpeg", - ]) - else: - raise ValueError(f"{track.__class__.__name__} not supported yet!") - - try: - p = subprocess.run(arguments, check=True) - except subprocess.CalledProcessError: - raise ValueError("N_m3u8DL-RE failed too many times, aborting") - print() + print() diff --git a/vinetrimmer/utils/playready/__init__.py b/vinetrimmer/utils/playready/__init__.py new file mode 100644 index 0000000..ec77f83 --- /dev/null +++ b/vinetrimmer/utils/playready/__init__.py @@ -0,0 +1,13 @@ +from .bcert import * +from .cdm import * +from .device import * +from .ecc_key import * +from .elgamal import * +from .key import * +from .pssh import * +from .remotecdm import * +from .session import * +from .xml_key import * +from .xmrlicense import * + +__version__ = "0.4.2" diff --git a/scripts/pyplayready/pyplayready/system/bcert.py b/vinetrimmer/utils/playready/bcert.py similarity index 80% rename from scripts/pyplayready/pyplayready/system/bcert.py rename to vinetrimmer/utils/playready/bcert.py index f6a1b2c..832cedd 100644 --- a/scripts/pyplayready/pyplayready/system/bcert.py +++ b/vinetrimmer/utils/playready/bcert.py @@ -3,8 +3,7 @@ import collections.abc from Crypto.PublicKey import ECC -from pyplayready.crypto import Crypto -from pyplayready.exceptions import InvalidCertificateChain, InvalidCertificate +from .exceptions import InvalidCertificateChain # monkey patch for construct 2.8.8 compatibility if not hasattr(collections, 'Sequence'): @@ -14,11 +13,13 @@ import base64 from pathlib import Path from typing import Union +from Crypto.Hash import SHA256 +from Crypto.Signature import DSS from construct import Bytes, Const, Int32ub, GreedyRange, Switch, Container, ListContainer from construct import Int16ub, Array from construct import Struct, this -from pyplayready.crypto.ecc_key import ECCKey +from .ecc_key import ECCKey class _BCertStructs: @@ -106,7 +107,7 @@ class _BCertStructs: "key_type" / Int16ub, "key_length" / Int16ub, "flags" / Int32ub, - "key" / Bytes(this.key_length // 8) + "key" / Bytes(this.length // 8) ) # TODO: untested @@ -208,8 +209,16 @@ class Certificate(_BCertStructs): encryption_key: ECCKey, group_key: ECCKey, parent: CertificateChain, - expiry: int = 0xFFFFFFFF + expiry: int = 0xFFFFFFFF, + max_license: int = 10240, + max_header: int = 15360, + max_chain_depth: int = 2 ) -> Certificate: + if not cert_id: + raise ValueError("Certificate ID is required") + if not client_id: + raise ValueError("Client ID is required") + basic_info = Container( cert_id=cert_id, security_level=security_level, @@ -227,9 +236,9 @@ class Certificate(_BCertStructs): ) device_info = Container( - max_license=10240, - max_header=15360, - max_chain_depth=2 + max_license=max_license, + max_header=max_header, + max_chain_depth=max_chain_depth ) device_info_attribute = Container( flags=1, @@ -241,20 +250,9 @@ class Certificate(_BCertStructs): feature = Container( feature_count=3, features=ListContainer([ - # 1, # Transmitter - # 2, # Receiver - # 3, # SharedCertificate - 4, # SecureClock - # 5, # AntiRollBackClock - # 6, # ReservedMetering - # 7, # ReservedLicSync - # 8, # ReservedSymOpt - 9, # CRLS (Revocation Lists) - # 10, # ServerBasicEdition - # 11, # ServerStandardEdition - # 12, # ServerPremiumEdition - 13, # PlayReady3Features - # 14, # DeprecatedSecureStop + 4, # SECURE_CLOCK + 9, # REVOCATION_LIST_FEATURE + 13 # SUPPORTS_PR3_FEATURES ]) ) feature_attribute = Container( @@ -298,7 +296,7 @@ class Certificate(_BCertStructs): attribute=key_info ) - manufacturer_info = parent.get(0).get_attribute(7) + manufacturer_info = parent.get_certificate(0).get_attribute(7) new_bcert_container = Container( signature=b"CERT", @@ -319,7 +317,10 @@ class Certificate(_BCertStructs): new_bcert_container.total_length = len(payload) + 144 # signature length sign_payload = _BCertStructs.BCert.build(new_bcert_container) - signature = Crypto.ecc256_sign(group_key, sign_payload) + + hash_obj = SHA256.new(sign_payload) + signer = DSS.new(group_key.key, 'fips-186-3') + signature = signer.sign(hash_obj) signature_info = Container( signature_type=1, @@ -351,6 +352,13 @@ class Certificate(_BCertStructs): bcert_obj=cert ) + @classmethod + def load(cls, path: Union[Path, str]) -> Certificate: + if not isinstance(path, (Path, str)): + raise ValueError(f"Expecting Path object or path string, got {path!r}") + with Path(path).open(mode="rb") as f: + return cls.loads(f.read()) + def get_attribute(self, type_: int): for attribute in self.parsed.attributes: if attribute.tag == type_: @@ -370,54 +378,36 @@ class Certificate(_BCertStructs): if manufacturer_info: return f"{self._unpad(manufacturer_info.manufacturer_name)} {self._unpad(manufacturer_info.model_name)} {self._unpad(manufacturer_info.model_number)}" - def get_issuer_key(self) -> Union[bytes, None]: - key_info_object = self.get_attribute(6) - if not key_info_object: - return - - key_info_attribute = key_info_object.attribute - return next(map(lambda key: key.key, filter(lambda key: 6 in key.usages, key_info_attribute.cert_keys)), None) - def dumps(self) -> bytes: return self._BCERT.build(self.parsed) def struct(self) -> _BCertStructs.BCert: return self._BCERT - def verify(self, public_key: bytes, index: int): - signature_object = self.get_attribute(8) - if not signature_object: - raise InvalidCertificate(f"No signature object found in certificate {index}") - - signature_attribute = signature_object.attribute + def verify_signature(self): + sign_payload = self.dumps()[:-144] + signature_attribute = self.get_attribute(8).attribute raw_signature_key = signature_attribute.signature_key - if public_key != raw_signature_key: - raise InvalidCertificate(f"Signature keys of certificate {index} do not match") - signature_key = ECC.construct( curve='P-256', point_x=int.from_bytes(raw_signature_key[:32], 'big'), point_y=int.from_bytes(raw_signature_key[32:], 'big') ) - sign_payload = self.dumps()[:-signature_object.length] + hash_obj = SHA256.new(sign_payload) + verifier = DSS.new(signature_key, 'fips-186-3') - if not Crypto.ecc256_verify( - public_key=signature_key, - data=sign_payload, - signature=signature_attribute.signature - ): - raise InvalidCertificate(f"Signature of certificate {index} is not authentic") - - return self.get_issuer_key() + try: + verifier.verify(hash_obj, signature_attribute.signature) + return True + except ValueError: + return False class CertificateChain(_BCertStructs): """Represents a BCertChain""" - ECC256MSBCertRootIssuerPubKey = bytes.fromhex("864d61cff2256e422c568b3c28001cfb3e1527658584ba0521b79b1828d936de1d826a8fc3e6e7fa7a90d5ca2946f1f64a2efb9f5dcffe7e434eb44293fac5ab") - def __init__( self, parsed_bcert_chain: Container, @@ -452,27 +442,15 @@ class CertificateChain(_BCertStructs): def struct(self) -> _BCertStructs.BCertChain: return self._BCERT_CHAIN + def get_certificate(self, index: int) -> Certificate: + return Certificate(self.parsed.certificates[index]) + def get_security_level(self) -> int: # not sure if there's a better way than this - return self.get(0).get_security_level() + return self.get_certificate(0).get_security_level() def get_name(self) -> str: - return self.get(0).get_name() - - def verify(self) -> bool: - issuer_key = self.ECC256MSBCertRootIssuerPubKey - - try: - for i in reversed(range(self.count())): - certificate = self.get(i) - issuer_key = certificate.verify(issuer_key, i) - - if not issuer_key and i != 0: - raise InvalidCertificate(f"Certificate {i} is not valid") - except InvalidCertificate as e: - raise InvalidCertificateChain(e) - - return True + return self.get_certificate(0).get_name() def append(self, bcert: Certificate) -> None: self.parsed.certificate_count += 1 @@ -485,20 +463,21 @@ class CertificateChain(_BCertStructs): self.parsed.total_length += len(bcert.dumps()) def remove(self, index: int) -> None: - if self.count() <= 0: + if self.parsed.certificate_count <= 0: raise InvalidCertificateChain("CertificateChain does not contain any Certificates") - if index >= self.count(): - raise IndexError(f"No Certificate at index {index}, {self.count()} total") + if index >= self.parsed.certificate_count: + raise IndexError(f"No Certificate at index {index}, {self.parsed.certificate_count} total") self.parsed.certificate_count -= 1 - self.parsed.total_length -= len(self.get(index).dumps()) + bcert = Certificate(self.parsed.certificates[index]) + self.parsed.total_length -= len(bcert.dumps()) self.parsed.certificates.pop(index) def get(self, index: int) -> Certificate: - if self.count() <= 0: + if self.parsed.certificate_count <= 0: raise InvalidCertificateChain("CertificateChain does not contain any Certificates") - if index >= self.count(): - raise IndexError(f"No Certificate at index {index}, {self.count()} total") + if index >= self.parsed.certificate_count: + raise IndexError(f"No Certificate at index {index}, {self.parsed.certificate_count} total") return Certificate(self.parsed.certificates[index]) diff --git a/scripts/pyplayready/pyplayready/cdm.py b/vinetrimmer/utils/playready/cdm.py similarity index 71% rename from scripts/pyplayready/pyplayready/cdm.py rename to vinetrimmer/utils/playready/cdm.py index d56f890..9278720 100644 --- a/scripts/pyplayready/pyplayready/cdm.py +++ b/vinetrimmer/utils/playready/cdm.py @@ -10,20 +10,23 @@ import xml.etree.ElementTree as ET from Crypto.Cipher import AES from Crypto.Hash import SHA256 from Crypto.Random import get_random_bytes +from Crypto.Signature import DSS from Crypto.Util.Padding import pad - from ecpy.curves import Point, Curve -from pyplayready.crypto import Crypto -from pyplayready.system.bcert import CertificateChain -from pyplayready.crypto.ecc_key import ECCKey -from pyplayready.license.key import Key -from pyplayready.license.xmrlicense import XMRLicense -from pyplayready.exceptions import (InvalidSession, TooManySessions, InvalidLicense) -from pyplayready.system.session import Session +from .bcert import CertificateChain +from .ecc_key import ECCKey +from .key import Key +from .xml_key import XmlKey +from .elgamal import ElGamal +from .xmrlicense import XMRLicense + +from .exceptions import (InvalidSession, TooManySessions, InvalidLicense) +from .session import Session class Cdm: + MAX_NUM_OF_SESSIONS = 16 def __init__( @@ -42,13 +45,14 @@ class Cdm: self.client_version = client_version self.protocol_version = protocol_version - self.__crypto = Crypto() + self.curve = Curve.get_curve("secp256r1") + self.elgamal = ElGamal(self.curve) + self._wmrm_key = Point( x=0xc8b6af16ee941aadaa5389b4af2c10e356be42af175ef3face93254e7b0b3d9b, y=0x982b27b5cb2341326e56aa857dbfd5c634ce2cf9ea74fca8f2af5957efeea562, - curve=Curve.get_curve("secp256r1") + curve=self.curve ) - self._rgbMagicConstantZero = bytes([0x7e, 0xe9, 0xed, 0x4a, 0xf7, 0x73, 0x22, 0x4f, 0x00, 0xb8, 0xea, 0x7e, 0xfb, 0x02, 0x7c, 0xbb]) self.__sessions: dict[bytes, Session] = {} @@ -74,6 +78,7 @@ class Cdm: session = Session(len(self.__sessions) + 1) self.__sessions[session.id] = session + session.xml_key = XmlKey() return session.id @@ -93,24 +98,15 @@ class Cdm: del self.__sessions[session_id] def _get_key_data(self, session: Session) -> bytes: - return self.__crypto.ecc256_encrypt( - public_key=self._wmrm_key, - plaintext=session.xml_key.get_point() + point1, point2 = self.elgamal.encrypt( + message_point=session.xml_key.get_point(self.elgamal.curve), + public_key=self._wmrm_key ) + return self.elgamal.to_bytes(point1.x) + self.elgamal.to_bytes(point1.y) + self.elgamal.to_bytes(point2.x) + self.elgamal.to_bytes(point2.y) def _get_cipher_data(self, session: Session) -> bytes: b64_chain = base64.b64encode(self.certificate_chain.dumps()).decode() - body = ( - "" - f"{b64_chain}" - "" - '""' - "" - "" - "" - "" - "" - ) + body = f"{b64_chain}" cipher = AES.new( key=session.xml_key.aes_key, @@ -194,7 +190,10 @@ class Cdm: la_hash = la_hash_obj.digest() signed_info = self._build_signed_info(base64.b64encode(la_hash).decode()) - signature = self.__crypto.ecc256_sign(session.signing_key, signed_info.encode()) + signed_info_digest = SHA256.new(signed_info.encode()) + + signer = DSS.new(session.signing_key.key, 'fips-186-3') + signature = signer.sign(signed_info_digest) # haven't found a better way to do this. xmltodict.unparse doesn't work main_body = ( @@ -225,8 +224,23 @@ class Cdm: return main_body + def _decrypt_ecc256_key(self, session: Session, encrypted_key: bytes) -> bytes: + point1 = Point( + x=int.from_bytes(encrypted_key[:32], 'big'), + y=int.from_bytes(encrypted_key[32:64], 'big'), + curve=self.curve + ) + point2 = Point( + x=int.from_bytes(encrypted_key[64:96], 'big'), + y=int.from_bytes(encrypted_key[96:128], 'big'), + curve=self.curve + ) + + decrypted = self.elgamal.decrypt((point1, point2), int(session.encryption_key.key.d)) + return self.elgamal.to_bytes(decrypted.x)[16:32] + @staticmethod - def _verify_encryption_key(session: Session, licence: XMRLicense) -> bool: + def _verify_ecc_key(session: Session, licence: XMRLicense) -> bool: ecc_keys = list(licence.get_object(42)) if not ecc_keys: raise InvalidLicense("No ECC public key in license") @@ -244,60 +258,21 @@ class Cdm: try: root = ET.fromstring(licence) license_elements = root.findall(".//{http://schemas.microsoft.com/DRM/2007/03/protocols}License") - for license_element in license_elements: parsed_licence = XMRLicense.loads(license_element.text) - if not self._verify_encryption_key(session, parsed_licence): + if not self._verify_ecc_key(session, parsed_licence): raise InvalidLicense("Public encryption key does not match") - is_scalable = bool(next(parsed_licence.get_object(81), None)) - - for content_key in parsed_licence.get_content_keys(): - cipher_type = Key.CipherType(content_key.cipher_type) - - if not cipher_type in (Key.CipherType.ECC_256, Key.CipherType.ECC_256_WITH_KZ, Key.CipherType.ECC_256_VIA_SYMMETRIC): - raise InvalidLicense(f"Invalid cipher type {cipher_type}") - - via_symmetric = Key.CipherType(content_key.cipher_type) == Key.CipherType.ECC_256_VIA_SYMMETRIC - - decrypted = self.__crypto.ecc256_decrypt( - private_key=session.encryption_key, - ciphertext=content_key.encrypted_key - ) - ci, ck = decrypted[:16], decrypted[16:32] - - if is_scalable: - ci, ck = decrypted[::2][:16], decrypted[1::2][:16] - - if via_symmetric: - embedded_root_license = content_key.encrypted_key[:144] - embedded_leaf_license = content_key.encrypted_key[144:] - - rgb_key = bytes(ck[i] ^ self._rgbMagicConstantZero[i] for i in range(16)) - content_key_prime = AES.new(ck, AES.MODE_ECB).encrypt(rgb_key) - - aux_key = next(parsed_licence.get_object(81))["auxiliary_keys"][0]["key"] - derived_aux_key = AES.new(content_key_prime, AES.MODE_ECB).encrypt(aux_key) - - uplink_x_key = bytes(bytearray(16)[i] ^ derived_aux_key[i] for i in range(16)) - secondary_key = AES.new(ck, AES.MODE_ECB).encrypt(embedded_root_license[128:]) - - embedded_leaf_license = AES.new(uplink_x_key, AES.MODE_ECB).encrypt(embedded_leaf_license) - embedded_leaf_license = AES.new(secondary_key, AES.MODE_ECB).encrypt(embedded_leaf_license) - - ci, ck = embedded_leaf_license[:16], embedded_leaf_license[16:] - - if not parsed_licence.check_signature(ci): - raise InvalidLicense("License integrity signature does not match") - - session.keys.append(Key( - key_id=UUID(bytes_le=content_key.key_id), - key_type=content_key.key_type, - cipher_type=content_key.cipher_type, - key_length=content_key.key_length, - key=ck - )) + for key in parsed_licence.get_content_keys(): + if Key.CipherType(key.cipher_type) == Key.CipherType.ECC_256: + session.keys.append(Key( + key_id=UUID(bytes_le=key.key_id), + key_type=key.key_type, + cipher_type=key.cipher_type, + key_length=key.key_length, + key=self._decrypt_ecc256_key(session, key.encrypted_key) + )) except InvalidLicense as e: raise InvalidLicense(e) except Exception as e: diff --git a/scripts/pyplayready/pyplayready/device/__init__.py b/vinetrimmer/utils/playready/device.py similarity index 64% rename from scripts/pyplayready/pyplayready/device/__init__.py rename to vinetrimmer/utils/playready/device.py index c4aaaf2..7322d8a 100644 --- a/scripts/pyplayready/pyplayready/device/__init__.py +++ b/vinetrimmer/utils/playready/device.py @@ -3,27 +3,67 @@ from __future__ import annotations import base64 from enum import IntEnum from pathlib import Path -from typing import Union, Any, Optional +from typing import Union, Any -from pyplayready.device.structs import DeviceStructs -from pyplayready.exceptions import OutdatedDevice -from pyplayready.system.bcert import CertificateChain -from pyplayready.crypto.ecc_key import ECCKey +from construct import Struct, Const, Int8ub, Bytes, this, Int32ub + +from .bcert import CertificateChain +from .ecc_key import ECCKey + + +class SecurityLevel(IntEnum): + SL150 = 150 + SL2000 = 2000 + SL3000 = 3000 + + +class _DeviceStructs: + magic = Const(b"PRD") + + header = Struct( + "signature" / magic, + "version" / Int8ub, + ) + + # was never in production + v1 = Struct( + "signature" / magic, + "version" / Int8ub, + "group_key_length" / Int32ub, + "group_key" / Bytes(this.group_key_length), + "group_certificate_length" / Int32ub, + "group_certificate" / Bytes(this.group_certificate_length) + ) + + v2 = Struct( + "signature" / magic, + "version" / Int8ub, + "group_certificate_length" / Int32ub, + "group_certificate" / Bytes(this.group_certificate_length), + "encryption_key" / Bytes(96), + "signing_key" / Bytes(96), + ) + + v3 = Struct( + "signature" / magic, + "version" / Int8ub, + "group_key" / Bytes(96), + "encryption_key" / Bytes(96), + "signing_key" / Bytes(96), + "group_certificate_length" / Int32ub, + "group_certificate" / Bytes(this.group_certificate_length), + ) class Device: """Represents a PlayReady Device (.prd)""" + CURRENT_STRUCT = _DeviceStructs.v3 CURRENT_VERSION = 3 - class SecurityLevel(IntEnum): - SL150 = 150 - SL2000 = 2000 - SL3000 = 3000 - def __init__( self, *_: Any, - group_key: Optional[str, bytes, None], + group_key: Union[str, bytes, None], encryption_key: Union[str, bytes], signing_key: Union[str, bytes], group_certificate: Union[str, bytes], @@ -60,11 +100,14 @@ class Device: if not isinstance(data, bytes): raise ValueError(f"Expecting Bytes or Base64 input, got {data!r}") - parsed = DeviceStructs.prd.parse(data) - return cls(**{ - **parsed, - 'group_key': parsed.get('group_key', None) - }) + prd_header = _DeviceStructs.header.parse(data) + if prd_header.version == 2: + return cls( + group_key=None, + **_DeviceStructs.v2.parse(data) + ) + + return cls(**cls.CURRENT_STRUCT.parse(data)) @classmethod def load(cls, path: Union[Path, str]) -> Device: @@ -74,10 +117,7 @@ class Device: return cls.loads(f.read()) def dumps(self) -> bytes: - if not self.group_key: - raise OutdatedDevice("Cannot dump a v2 device, re-create it or use a Device with a version of 3 or higher") - - return DeviceStructs.prd.build(dict( + return self.CURRENT_STRUCT.build(dict( version=self.CURRENT_VERSION, group_key=self.group_key.dumps(), encryption_key=self.encryption_key.dumps(), diff --git a/scripts/pyplayready/pyplayready/crypto/ecc_key.py b/vinetrimmer/utils/playready/ecc_key.py similarity index 80% rename from scripts/pyplayready/pyplayready/crypto/ecc_key.py rename to vinetrimmer/utils/playready/ecc_key.py index 2baab46..8a39d0f 100644 --- a/scripts/pyplayready/pyplayready/crypto/ecc_key.py +++ b/vinetrimmer/utils/playready/ecc_key.py @@ -11,7 +11,7 @@ from ecpy.curves import Curve, Point class ECCKey: - """Represents a PlayReady ECC key pair""" + """Represents a PlayReady ECC key""" def __init__(self, key: EccKey): self.key = key @@ -56,30 +56,21 @@ class ECCKey: with Path(path).open(mode="rb") as f: return cls.loads(f.read()) - def dumps(self, private_only=False): - if private_only: - return self.private_bytes() + def dumps(self): return self.private_bytes() + self.public_bytes() - def dump(self, path: Union[Path, str], private_only=False) -> None: + def dump(self, path: Union[Path, str]) -> None: if not isinstance(path, (Path, str)): raise ValueError(f"Expecting Path object or path string, got {path!r}") path = Path(path) path.parent.mkdir(parents=True, exist_ok=True) - path.write_bytes(self.dumps(private_only)) - - @staticmethod - def _to_bytes(n: int) -> bytes: - byte_len = (n.bit_length() + 7) // 8 - if byte_len % 2 != 0: - byte_len += 1 - return n.to_bytes(byte_len, 'big') + path.write_bytes(self.dumps()) def get_point(self, curve: Curve) -> Point: return Point(self.key.pointQ.x, self.key.pointQ.y, curve) def private_bytes(self) -> bytes: - return self._to_bytes(int(self.key.d)) + return self.key.d.to_bytes() def private_sha256_digest(self) -> bytes: hash_object = SHA256.new() @@ -87,7 +78,7 @@ class ECCKey: return hash_object.digest() def public_bytes(self) -> bytes: - return self._to_bytes(int(self.key.pointQ.x)) + self._to_bytes(int(self.key.pointQ.y)) + return self.key.pointQ.x.to_bytes() + self.key.pointQ.y.to_bytes() def public_sha256_digest(self) -> bytes: hash_object = SHA256.new() diff --git a/scripts/pyplayready/pyplayready/crypto/elgamal.py b/vinetrimmer/utils/playready/elgamal.py similarity index 100% rename from scripts/pyplayready/pyplayready/crypto/elgamal.py rename to vinetrimmer/utils/playready/elgamal.py diff --git a/scripts/pyplayready/pyplayready/exceptions.py b/vinetrimmer/utils/playready/exceptions.py similarity index 90% rename from scripts/pyplayready/pyplayready/exceptions.py rename to vinetrimmer/utils/playready/exceptions.py index a2ca2c3..9d0cbde 100644 --- a/scripts/pyplayready/pyplayready/exceptions.py +++ b/vinetrimmer/utils/playready/exceptions.py @@ -26,12 +26,8 @@ class InvalidLicense(PyPlayreadyException): """Unable to parse XMR License.""" -class InvalidCertificate(PyPlayreadyException): - """The BCert is not correctly formatted.""" - - class InvalidCertificateChain(PyPlayreadyException): - """The BCertChain is not correctly formatted.""" + """The BCert is not correctly formatted.""" class OutdatedDevice(PyPlayreadyException): diff --git a/scripts/pyplayready/pyplayready/license/key.py b/vinetrimmer/utils/playready/key.py similarity index 94% rename from scripts/pyplayready/pyplayready/license/key.py rename to vinetrimmer/utils/playready/key.py index 54ecca0..23cde0f 100644 --- a/scripts/pyplayready/pyplayready/license/key.py +++ b/vinetrimmer/utils/playready/key.py @@ -12,7 +12,6 @@ class Key: AES_128_ECB = 0x0003 COCKTAIL = 0x0004 AES_128_CBC = 0x0005 - KEYEXCHANGE = 0x0006 UNKNOWN = 0xffff @classmethod @@ -25,8 +24,7 @@ class Key: CHAINED_LICENSE = 0x0002 ECC_256 = 0x0003 ECC_256_WITH_KZ = 0x0004 - TEE_TRANSIENT = 0x0005 - ECC_256_VIA_SYMMETRIC = 0x0006 + SCALABLE = 0x0005 UNKNOWN = 0xffff @classmethod diff --git a/scripts/pyplayready/pyplayready/main.py b/vinetrimmer/utils/playready/main.py similarity index 90% rename from scripts/pyplayready/pyplayready/main.py rename to vinetrimmer/utils/playready/main.py index e18a927..aa43fb0 100644 --- a/scripts/pyplayready/pyplayready/main.py +++ b/vinetrimmer/utils/playready/main.py @@ -7,13 +7,13 @@ import click import requests from Crypto.Random import get_random_bytes -from pyplayready import __version__, InvalidCertificateChain -from pyplayready.system.bcert import CertificateChain, Certificate -from pyplayready.cdm import Cdm -from pyplayready.device import Device -from pyplayready.crypto.ecc_key import ECCKey -from pyplayready.exceptions import OutdatedDevice -from pyplayready.system.pssh import PSSH +from . import __version__ +from .bcert import CertificateChain, Certificate +from .cdm import Cdm +from .device import Device +from .ecc_key import ECCKey +from .exceptions import OutdatedDevice +from .pssh import PSSH @click.group(invoke_without_command=True) @@ -56,7 +56,7 @@ def license_(device_path: Path, pssh: PSSH, server: str) -> None: session_id = cdm.open() log.info("Opened Session") - challenge = cdm.get_license_challenge(session_id, pssh.get_wrm_headers()[0]) + challenge = cdm.get_license_challenge(session_id, pssh.get_wrm_headers(downgrade_to_v4=True)[0]) log.info("Created License Request (Challenge)") log.debug(challenge) @@ -69,7 +69,7 @@ def license_(device_path: Path, pssh: PSSH, server: str) -> None: ) if license_res.status_code != 200: - log.error(f"Failed to send challenge [{license_res.status_code}]: {license_res.text}") + log.error(f"Failed to send challenge: [{license_res.status_code}] {license_res.text}") return licence = license_res.text @@ -88,10 +88,8 @@ def license_(device_path: Path, pssh: PSSH, server: str) -> None: @main.command() @click.argument("device", type=Path) -@click.option("-c", "--ckt", type=click.Choice(["aesctr", "aescbc"], case_sensitive=False), default="aesctr", help="Content Key Encryption Type") -@click.option("-sl", "--security_level", type=click.Choice(["150", "2000", "3000"], case_sensitive=False), default="2000", help="Minimum Security Level") @click.pass_context -def test(ctx: click.Context, device: Path, ckt: str, security_level: str) -> None: +def test(ctx: click.Context, device: Path) -> None: """ Test the CDM code by getting Content Keys for the Tears Of Steel demo on the Playready Test Server. https://testweb.playready.microsoft.com/Content/Content2X @@ -115,7 +113,7 @@ def test(ctx: click.Context, device: Path, ckt: str, security_level: str) -> Non "AFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==" ) - license_server = f"https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:{security_level},ckt:{ckt})" + license_server = "https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:2000)" ctx.invoke( license_, @@ -150,9 +148,6 @@ def create_device( group_key = ECCKey.load(group_key) certificate_chain = CertificateChain.load(group_certificate) - if certificate_chain.get(0).get_issuer_key() != group_key.public_bytes(): - raise InvalidCertificateChain("Group key does not match this certificate") - new_certificate = Certificate.new_leaf_cert( cert_id=get_random_bytes(16), security_level=certificate_chain.get_security_level(), @@ -164,8 +159,6 @@ def create_device( ) certificate_chain.prepend(new_certificate) - certificate_chain.verify() - device = Device( group_key=group_key.dumps(), encryption_key=encryption_key.dumps(), @@ -286,7 +279,7 @@ def export_device(ctx: click.Context, prd_path: Path, out_dir: Optional[Path] = if device.group_key: group_key_path = out_path / "zgpriv.dat" - group_key_path.write_bytes(device.group_key.dumps(private_only=True)) + group_key_path.write_bytes(device.group_key.dumps()) log.info("Exported Group Key as zgpriv.dat") else: log.warning("Cannot export zgpriv.dat, as v2 devices do not save the group key") @@ -313,7 +306,7 @@ def serve_(config_path: Path, host: str, port: int) -> None: Host as 127.0.0.1 may block remote access even if port-forwarded. Instead, use 0.0.0.0 and ensure the TCP port you choose is forwarded. """ - from pyplayready.remote import serve + from pyplayready import serve import yaml config = yaml.safe_load(config_path.read_text(encoding="utf8")) diff --git a/scripts/pyplayready/pyplayready/system/pssh.py b/vinetrimmer/utils/playready/pssh.py similarity index 89% rename from scripts/pyplayready/pyplayready/system/pssh.py rename to vinetrimmer/utils/playready/pssh.py index 16f6f12..815ffb5 100644 --- a/scripts/pyplayready/pyplayready/system/pssh.py +++ b/vinetrimmer/utils/playready/pssh.py @@ -4,8 +4,8 @@ from uuid import UUID from construct import Struct, Int32ul, Int16ul, Array, this, Bytes, Switch, Int32ub, Const, Container, ConstructError -from pyplayready.exceptions import InvalidPssh -from pyplayready.system.wrmheader import WRMHeader +from .exceptions import InvalidPssh +from .wrmheader import WRMHeader class _PlayreadyPSSHStructs: @@ -86,11 +86,13 @@ class PSSH(_PlayreadyPSSHStructs): ) )) - def get_wrm_headers(self) -> List[str]: + def get_wrm_headers(self, downgrade_to_v4: bool = False) -> List[str]: """ Return a list of all WRM Headers in the PSSH as plaintext strings + + downgrade_to_v4: Downgrade the WRM Header to version 4.0.0.0 to use AES-CBC instead of AES-CTR """ return list(map( - lambda wrm_header: wrm_header.dumps(), + lambda wrm_header: wrm_header.to_v4_0_0_0() if downgrade_to_v4 else wrm_header.dumps(), self.wrm_headers )) diff --git a/scripts/pyplayready/pyplayready/remote/remotecdm.py b/vinetrimmer/utils/playready/remotecdm.py similarity index 96% rename from scripts/pyplayready/pyplayready/remote/remotecdm.py rename to vinetrimmer/utils/playready/remotecdm.py index 9afd6b3..73c88db 100644 --- a/scripts/pyplayready/pyplayready/remote/remotecdm.py +++ b/vinetrimmer/utils/playready/remotecdm.py @@ -4,11 +4,11 @@ import re import requests -from pyplayready.cdm import Cdm -from pyplayready.device import Device -from pyplayready.license.key import Key +from .cdm import Cdm +from .device import Device +from .key import Key -from pyplayready.exceptions import (DeviceMismatch, InvalidInitData) +from .exceptions import (DeviceMismatch, InvalidInitData) class RemoteCdm(Cdm): diff --git a/scripts/pyplayready/pyplayready/remote/serve.py b/vinetrimmer/utils/playready/serve.py similarity index 97% rename from scripts/pyplayready/pyplayready/remote/serve.py rename to vinetrimmer/utils/playready/serve.py index 64a0b69..fd928c1 100644 --- a/scripts/pyplayready/pyplayready/remote/serve.py +++ b/vinetrimmer/utils/playready/serve.py @@ -1,14 +1,15 @@ +import base64 from pathlib import Path from typing import Any, Optional, Union from aiohttp.typedefs import Handler from aiohttp import web -from pyplayready import __version__, PSSH -from pyplayready.cdm import Cdm -from pyplayready.device import Device +from . import __version__, PSSH +from .cdm import Cdm +from .device import Device -from pyplayready.exceptions import (InvalidSession, TooManySessions, InvalidLicense, InvalidPssh) +from .exceptions import (InvalidSession, TooManySessions, InvalidLicense, InvalidPssh) routes = web.RouteTableDef() @@ -136,7 +137,7 @@ async def get_license_challenge(request: web.Request) -> web.Response: if not init_data.startswith(" str: + """ + Build a v4.0.0.0 WRM header from any possible WRM Header version + + Note: Will ignore any remaining Key IDs if there's more than just one + """ + return self._build_v4_0_0_0_wrm_header(*self.read_attributes()) + @staticmethod def _read_v4_0_0_0(data: dict) -> _RETURN_STRUCTURE: protect_info = data.get("PROTECTINFO") @@ -148,6 +156,7 @@ class WRMHeader: Returns a tuple structured like this: Tuple[List[SignedKeyID], , , ] """ + data = self._header.get("DATA") if not data: raise ValueError("Not a valid PlayReady Header Record, WRMHEADER/DATA required") @@ -161,5 +170,32 @@ class WRMHeader: elif self.version == self.Version.VERSION_4_3_0_0: return self._read_v4_3_0_0(data) + @staticmethod + def _build_v4_0_0_0_wrm_header( + key_ids: List[SignedKeyID], + la_url: Optional[str], + lui_url: Optional[str], + ds_id: Optional[str] + ) -> str: + if len(key_ids) == 0: + raise Exception("No Key IDs available") + + key_id = key_ids[0] + return ( + '' + '' + '' + '16' + 'AESCTR' + '' + f'{key_id.value}' + + (f'{la_url}' if la_url else '') + + (f'{lui_url}' if lui_url else '') + + (f'{ds_id}' if ds_id else '') + + (f'{key_id.checksum}' if key_id.checksum else '') + + '' + '' + ) + def dumps(self) -> str: return self._raw_data.decode("utf-16-le") diff --git a/scripts/pyplayready/pyplayready/license/xml_key.py b/vinetrimmer/utils/playready/xml_key.py similarity index 65% rename from scripts/pyplayready/pyplayready/license/xml_key.py rename to vinetrimmer/utils/playready/xml_key.py index cc501fd..6075032 100644 --- a/scripts/pyplayready/pyplayready/license/xml_key.py +++ b/vinetrimmer/utils/playready/xml_key.py @@ -1,15 +1,13 @@ from ecpy.curves import Point, Curve -from pyplayready.crypto.ecc_key import ECCKey -from pyplayready.crypto.elgamal import ElGamal +from .ecc_key import ECCKey +from .elgamal import ElGamal class XmlKey: """Represents a PlayReady XMLKey""" def __init__(self): - self.curve = Curve.get_curve("secp256r1") - self._shared_point = ECCKey.generate() self.shared_key_x = self._shared_point.key.pointQ.x self.shared_key_y = self._shared_point.key.pointQ.y @@ -18,5 +16,5 @@ class XmlKey: self.aes_iv = self._shared_key_x_bytes[:16] self.aes_key = self._shared_key_x_bytes[16:] - def get_point(self) -> Point: - return Point(self.shared_key_x, self.shared_key_y, self.curve) + def get_point(self, curve: Curve) -> Point: + return Point(self.shared_key_x, self.shared_key_y, curve) diff --git a/scripts/pyplayready/pyplayready/license/xmrlicense.py b/vinetrimmer/utils/playready/xmrlicense.py similarity index 93% rename from scripts/pyplayready/pyplayready/license/xmrlicense.py rename to vinetrimmer/utils/playready/xmrlicense.py index 1e0421d..bdc92a9 100644 --- a/scripts/pyplayready/pyplayready/license/xmrlicense.py +++ b/vinetrimmer/utils/playready/xmrlicense.py @@ -1,10 +1,9 @@ from __future__ import annotations import base64 +from pathlib import Path from typing import Union -from Crypto.Cipher import AES -from Crypto.Hash import CMAC from construct import Const, GreedyRange, Struct, Int32ub, Bytes, Int16ub, this, Switch, LazyBound, Array, Container @@ -99,7 +98,7 @@ class _XMRLicenseStructs: PolicyMetadataObject = Struct( "metadata_type" / Bytes(16), - "policy_data" / Bytes(this._.length - 24) + "policy_data" / Bytes(this._.length) ) SecureStopRestrictionObject = Struct( @@ -224,6 +223,13 @@ class XMRLicense(_XMRLicenseStructs): license_obj=licence ) + @classmethod + def load(cls, path: Union[Path, str]) -> XMRLicense: + if not isinstance(path, (Path, str)): + raise ValueError(f"Expecting Path object or path string, got {path!r}") + with Path(path).open(mode="rb") as f: + return cls.loads(f.read()) + def dumps(self) -> bytes: return self._license_obj.build(self.parsed) @@ -243,12 +249,5 @@ class XMRLicense(_XMRLicenseStructs): yield container.data def get_content_keys(self): - yield from self.get_object(10) - - def check_signature(self, integrity_key: bytes) -> bool: - cmac = CMAC.new(integrity_key, ciphermod=AES) - - signature_data = next(self.get_object(11)) - cmac.update(self.dumps()[:-(signature_data.signature_data_length + 12)]) - - return signature_data.signature_data == cmac.digest() + for content_key in self.get_object(10): + yield content_key diff --git a/vinetrimmer/utils/widevine/device.py b/vinetrimmer/utils/widevine/device.py index 88e1684..a7c3e9c 100644 --- a/vinetrimmer/utils/widevine/device.py +++ b/vinetrimmer/utils/widevine/device.py @@ -19,7 +19,7 @@ from Cryptodome.PublicKey import RSA from Cryptodome.Random import get_random_bytes from Cryptodome.Signature import pss from Cryptodome.Util import Padding as CPadding -from protobuf3.message import DecodeError +from google.protobuf.message import DecodeError from vinetrimmer.utils.widevine.key import Key from vinetrimmer.utils.widevine.protos import widevine_pb2 as widevine @@ -340,7 +340,7 @@ class LocalDevice(BaseDevice): class RemoteDevice(BaseDevice): - def __init__(self, *_, name, host, username, key, device=None, type, system_id, security_level, **__): + def __init__(self, *_, type, system_id, security_level, name, host, username, key, device=None, **__): self.type = self.Types[type] if isinstance(type, str) else type self.system_id = system_id self.security_level = security_level diff --git a/vinetrimmer/utils/widevine/protos/widevine_pb2.py b/vinetrimmer/utils/widevine/protos/widevine_pb2.py index 73c5400..7fd57a9 100644 --- a/vinetrimmer/utils/widevine/protos/widevine_pb2.py +++ b/vinetrimmer/utils/widevine/protos/widevine_pb2.py @@ -4,11 +4,11 @@ import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) -from protobuf3 import descriptor as _descriptor -from protobuf3 import message -from protobuf3 import reflection as _reflection -from protobuf3 import symbol_database as _symbol_database -from protobuf3.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import enum_type_wrapper # @@protoc_insertion_point(imports) @@ -522,7 +522,7 @@ _PROVISIONINGOPTIONS_CERTIFICATETYPE = _descriptor.EnumDescriptor( ) _sym_db.RegisterEnumDescriptor(_PROVISIONINGOPTIONS_CERTIFICATETYPE) -_SIGNEDMESSAGEmessageTYPE = _descriptor.EnumDescriptor( +_SIGNEDMESSAGE_MESSAGETYPE = _descriptor.EnumDescriptor( name='MessageType', full_name='SignedMessage.MessageType', filename=None, @@ -554,7 +554,7 @@ _SIGNEDMESSAGEmessageTYPE = _descriptor.EnumDescriptor( serialized_start=8206, serialized_end=8331, ) -_sym_db.RegisterEnumDescriptor(_SIGNEDMESSAGEmessageTYPE) +_sym_db.RegisterEnumDescriptor(_SIGNEDMESSAGE_MESSAGETYPE) _WIDEVINECENCHEADER_ALGORITHM = _descriptor.EnumDescriptor( name='Algorithm', @@ -578,7 +578,7 @@ _WIDEVINECENCHEADER_ALGORITHM = _descriptor.EnumDescriptor( ) _sym_db.RegisterEnumDescriptor(_WIDEVINECENCHEADER_ALGORITHM) -_SIGNEDLICENSEREQUESTmessageTYPE = _descriptor.EnumDescriptor( +_SIGNEDLICENSEREQUEST_MESSAGETYPE = _descriptor.EnumDescriptor( name='MessageType', full_name='SignedLicenseRequest.MessageType', filename=None, @@ -610,9 +610,9 @@ _SIGNEDLICENSEREQUESTmessageTYPE = _descriptor.EnumDescriptor( serialized_start=8206, serialized_end=8331, ) -_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEREQUESTmessageTYPE) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEREQUEST_MESSAGETYPE) -_SIGNEDLICENSEREQUESTRAWmessageTYPE = _descriptor.EnumDescriptor( +_SIGNEDLICENSEREQUESTRAW_MESSAGETYPE = _descriptor.EnumDescriptor( name='MessageType', full_name='SignedLicenseRequestRaw.MessageType', filename=None, @@ -644,9 +644,9 @@ _SIGNEDLICENSEREQUESTRAWmessageTYPE = _descriptor.EnumDescriptor( serialized_start=8206, serialized_end=8331, ) -_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEREQUESTRAWmessageTYPE) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEREQUESTRAW_MESSAGETYPE) -_SIGNEDLICENSEmessageTYPE = _descriptor.EnumDescriptor( +_SIGNEDLICENSE_MESSAGETYPE = _descriptor.EnumDescriptor( name='MessageType', full_name='SignedLicense.MessageType', filename=None, @@ -678,9 +678,9 @@ _SIGNEDLICENSEmessageTYPE = _descriptor.EnumDescriptor( serialized_start=8206, serialized_end=8331, ) -_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSEmessageTYPE) +_sym_db.RegisterEnumDescriptor(_SIGNEDLICENSE_MESSAGETYPE) -_SIGNEDSERVICECERTIFICATEmessageTYPE = _descriptor.EnumDescriptor( +_SIGNEDSERVICECERTIFICATE_MESSAGETYPE = _descriptor.EnumDescriptor( name='MessageType', full_name='SignedServiceCertificate.MessageType', filename=None, @@ -712,7 +712,7 @@ _SIGNEDSERVICECERTIFICATEmessageTYPE = _descriptor.EnumDescriptor( serialized_start=8206, serialized_end=8331, ) -_sym_db.RegisterEnumDescriptor(_SIGNEDSERVICECERTIFICATEmessageTYPE) +_sym_db.RegisterEnumDescriptor(_SIGNEDSERVICECERTIFICATE_MESSAGETYPE) _CLIENTIDENTIFICATION_NAMEVALUE = _descriptor.Descriptor( @@ -2900,7 +2900,7 @@ _SIGNEDMESSAGE = _descriptor.Descriptor( ], nested_types=[], enum_types=[ - _SIGNEDMESSAGEmessageTYPE, + _SIGNEDMESSAGE_MESSAGETYPE, ], serialized_options=None, is_extendable=False, @@ -3055,7 +3055,7 @@ _SIGNEDLICENSEREQUEST = _descriptor.Descriptor( ], nested_types=[], enum_types=[ - _SIGNEDLICENSEREQUESTmessageTYPE, + _SIGNEDLICENSEREQUEST_MESSAGETYPE, ], serialized_options=None, is_extendable=False, @@ -3115,7 +3115,7 @@ _SIGNEDLICENSEREQUESTRAW = _descriptor.Descriptor( ], nested_types=[], enum_types=[ - _SIGNEDLICENSEREQUESTRAWmessageTYPE, + _SIGNEDLICENSEREQUESTRAW_MESSAGETYPE, ], serialized_options=None, is_extendable=False, @@ -3175,7 +3175,7 @@ _SIGNEDLICENSE = _descriptor.Descriptor( ], nested_types=[], enum_types=[ - _SIGNEDLICENSEmessageTYPE, + _SIGNEDLICENSE_MESSAGETYPE, ], serialized_options=None, is_extendable=False, @@ -3235,7 +3235,7 @@ _SIGNEDSERVICECERTIFICATE = _descriptor.Descriptor( ], nested_types=[], enum_types=[ - _SIGNEDSERVICECERTIFICATEmessageTYPE, + _SIGNEDSERVICECERTIFICATE_MESSAGETYPE, ], serialized_options=None, is_extendable=False, @@ -3441,27 +3441,27 @@ _REMOTEATTESTATION.fields_by_name['Certificate'].message_type = _ENCRYPTEDCLIENT _SIGNEDDEVICECERTIFICATE.fields_by_name['_DeviceCertificate'].message_type = _DEVICECERTIFICATE _SIGNEDDEVICECERTIFICATE.fields_by_name['Signer'].message_type = _SIGNEDDEVICECERTIFICATE _SIGNEDPROVISIONINGMESSAGE.fields_by_name['protocol_version'].enum_type = _PROTOCOLVERSION -_SIGNEDMESSAGE.fields_by_name['Type'].enum_type = _SIGNEDMESSAGEmessageTYPE +_SIGNEDMESSAGE.fields_by_name['Type'].enum_type = _SIGNEDMESSAGE_MESSAGETYPE _SIGNEDMESSAGE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION -_SIGNEDMESSAGEmessageTYPE.containing_type = _SIGNEDMESSAGE +_SIGNEDMESSAGE_MESSAGETYPE.containing_type = _SIGNEDMESSAGE _WIDEVINECENCHEADER.fields_by_name['algorithm'].enum_type = _WIDEVINECENCHEADER_ALGORITHM _WIDEVINECENCHEADER_ALGORITHM.containing_type = _WIDEVINECENCHEADER -_SIGNEDLICENSEREQUEST.fields_by_name['Type'].enum_type = _SIGNEDLICENSEREQUESTmessageTYPE +_SIGNEDLICENSEREQUEST.fields_by_name['Type'].enum_type = _SIGNEDLICENSEREQUEST_MESSAGETYPE _SIGNEDLICENSEREQUEST.fields_by_name['Msg'].message_type = _LICENSEREQUEST _SIGNEDLICENSEREQUEST.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION -_SIGNEDLICENSEREQUESTmessageTYPE.containing_type = _SIGNEDLICENSEREQUEST -_SIGNEDLICENSEREQUESTRAW.fields_by_name['Type'].enum_type = _SIGNEDLICENSEREQUESTRAWmessageTYPE +_SIGNEDLICENSEREQUEST_MESSAGETYPE.containing_type = _SIGNEDLICENSEREQUEST +_SIGNEDLICENSEREQUESTRAW.fields_by_name['Type'].enum_type = _SIGNEDLICENSEREQUESTRAW_MESSAGETYPE _SIGNEDLICENSEREQUESTRAW.fields_by_name['Msg'].message_type = _LICENSEREQUESTRAW _SIGNEDLICENSEREQUESTRAW.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION -_SIGNEDLICENSEREQUESTRAWmessageTYPE.containing_type = _SIGNEDLICENSEREQUESTRAW -_SIGNEDLICENSE.fields_by_name['Type'].enum_type = _SIGNEDLICENSEmessageTYPE +_SIGNEDLICENSEREQUESTRAW_MESSAGETYPE.containing_type = _SIGNEDLICENSEREQUESTRAW +_SIGNEDLICENSE.fields_by_name['Type'].enum_type = _SIGNEDLICENSE_MESSAGETYPE _SIGNEDLICENSE.fields_by_name['Msg'].message_type = _LICENSE _SIGNEDLICENSE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION -_SIGNEDLICENSEmessageTYPE.containing_type = _SIGNEDLICENSE -_SIGNEDSERVICECERTIFICATE.fields_by_name['Type'].enum_type = _SIGNEDSERVICECERTIFICATEmessageTYPE +_SIGNEDLICENSE_MESSAGETYPE.containing_type = _SIGNEDLICENSE +_SIGNEDSERVICECERTIFICATE.fields_by_name['Type'].enum_type = _SIGNEDSERVICECERTIFICATE_MESSAGETYPE _SIGNEDSERVICECERTIFICATE.fields_by_name['Msg'].message_type = _SIGNEDDEVICECERTIFICATE _SIGNEDSERVICECERTIFICATE.fields_by_name['RemoteAttestation'].message_type = _REMOTEATTESTATION -_SIGNEDSERVICECERTIFICATEmessageTYPE.containing_type = _SIGNEDSERVICECERTIFICATE +_SIGNEDSERVICECERTIFICATE_MESSAGETYPE.containing_type = _SIGNEDSERVICECERTIFICATE _FILEHASHES_SIGNATURE.containing_type = _FILEHASHES _FILEHASHES.fields_by_name['signatures'].message_type = _FILEHASHES_SIGNATURE DESCRIPTOR.message_types_by_name['ClientIdentification'] = _CLIENTIDENTIFICATION @@ -3496,16 +3496,16 @@ DESCRIPTOR.enum_types_by_name['LicenseType'] = _LICENSETYPE DESCRIPTOR.enum_types_by_name['ProtocolVersion'] = _PROTOCOLVERSION _sym_db.RegisterFileDescriptor(DESCRIPTOR) -ClientIdentification = _reflection.GeneratedProtocolMessageType('ClientIdentification', (message.Message,), dict( +ClientIdentification = _reflection.GeneratedProtocolMessageType('ClientIdentification', (_message.Message,), dict( - NameValue = _reflection.GeneratedProtocolMessageType('NameValue', (message.Message,), dict( + NameValue = _reflection.GeneratedProtocolMessageType('NameValue', (_message.Message,), dict( DESCRIPTOR = _CLIENTIDENTIFICATION_NAMEVALUE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:ClientIdentification.NameValue) )) , - ClientCapabilities = _reflection.GeneratedProtocolMessageType('ClientCapabilities', (message.Message,), dict( + ClientCapabilities = _reflection.GeneratedProtocolMessageType('ClientCapabilities', (_message.Message,), dict( DESCRIPTOR = _CLIENTIDENTIFICATION_CLIENTCAPABILITIES, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:ClientIdentification.ClientCapabilities) @@ -3519,16 +3519,16 @@ _sym_db.RegisterMessage(ClientIdentification) _sym_db.RegisterMessage(ClientIdentification.NameValue) _sym_db.RegisterMessage(ClientIdentification.ClientCapabilities) -ClientIdentificationRaw = _reflection.GeneratedProtocolMessageType('ClientIdentificationRaw', (message.Message,), dict( +ClientIdentificationRaw = _reflection.GeneratedProtocolMessageType('ClientIdentificationRaw', (_message.Message,), dict( - NameValue = _reflection.GeneratedProtocolMessageType('NameValue', (message.Message,), dict( + NameValue = _reflection.GeneratedProtocolMessageType('NameValue', (_message.Message,), dict( DESCRIPTOR = _CLIENTIDENTIFICATIONRAW_NAMEVALUE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:ClientIdentificationRaw.NameValue) )) , - ClientCapabilities = _reflection.GeneratedProtocolMessageType('ClientCapabilities', (message.Message,), dict( + ClientCapabilities = _reflection.GeneratedProtocolMessageType('ClientCapabilities', (_message.Message,), dict( DESCRIPTOR = _CLIENTIDENTIFICATIONRAW_CLIENTCAPABILITIES, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:ClientIdentificationRaw.ClientCapabilities) @@ -3542,74 +3542,74 @@ _sym_db.RegisterMessage(ClientIdentificationRaw) _sym_db.RegisterMessage(ClientIdentificationRaw.NameValue) _sym_db.RegisterMessage(ClientIdentificationRaw.ClientCapabilities) -DeviceCertificate = _reflection.GeneratedProtocolMessageType('DeviceCertificate', (message.Message,), dict( +DeviceCertificate = _reflection.GeneratedProtocolMessageType('DeviceCertificate', (_message.Message,), dict( DESCRIPTOR = _DEVICECERTIFICATE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:DeviceCertificate) )) _sym_db.RegisterMessage(DeviceCertificate) -DeviceCertificateStatus = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatus', (message.Message,), dict( +DeviceCertificateStatus = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatus', (_message.Message,), dict( DESCRIPTOR = _DEVICECERTIFICATESTATUS, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:DeviceCertificateStatus) )) _sym_db.RegisterMessage(DeviceCertificateStatus) -DeviceCertificateStatusList = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatusList', (message.Message,), dict( +DeviceCertificateStatusList = _reflection.GeneratedProtocolMessageType('DeviceCertificateStatusList', (_message.Message,), dict( DESCRIPTOR = _DEVICECERTIFICATESTATUSLIST, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:DeviceCertificateStatusList) )) _sym_db.RegisterMessage(DeviceCertificateStatusList) -EncryptedClientIdentification = _reflection.GeneratedProtocolMessageType('EncryptedClientIdentification', (message.Message,), dict( +EncryptedClientIdentification = _reflection.GeneratedProtocolMessageType('EncryptedClientIdentification', (_message.Message,), dict( DESCRIPTOR = _ENCRYPTEDCLIENTIDENTIFICATION, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:EncryptedClientIdentification) )) _sym_db.RegisterMessage(EncryptedClientIdentification) -LicenseIdentification = _reflection.GeneratedProtocolMessageType('LicenseIdentification', (message.Message,), dict( +LicenseIdentification = _reflection.GeneratedProtocolMessageType('LicenseIdentification', (_message.Message,), dict( DESCRIPTOR = _LICENSEIDENTIFICATION, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:LicenseIdentification) )) _sym_db.RegisterMessage(LicenseIdentification) -License = _reflection.GeneratedProtocolMessageType('License', (message.Message,), dict( +License = _reflection.GeneratedProtocolMessageType('License', (_message.Message,), dict( - Policy = _reflection.GeneratedProtocolMessageType('Policy', (message.Message,), dict( + Policy = _reflection.GeneratedProtocolMessageType('Policy', (_message.Message,), dict( DESCRIPTOR = _LICENSE_POLICY, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:License.Policy) )) , - KeyContainer = _reflection.GeneratedProtocolMessageType('KeyContainer', (message.Message,), dict( + KeyContainer = _reflection.GeneratedProtocolMessageType('KeyContainer', (_message.Message,), dict( - OutputProtection = _reflection.GeneratedProtocolMessageType('OutputProtection', (message.Message,), dict( + OutputProtection = _reflection.GeneratedProtocolMessageType('OutputProtection', (_message.Message,), dict( DESCRIPTOR = _LICENSE_KEYCONTAINER_OUTPUTPROTECTION, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:License.KeyContainer.OutputProtection) )) , - KeyControl = _reflection.GeneratedProtocolMessageType('KeyControl', (message.Message,), dict( + KeyControl = _reflection.GeneratedProtocolMessageType('KeyControl', (_message.Message,), dict( DESCRIPTOR = _LICENSE_KEYCONTAINER_KEYCONTROL, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:License.KeyContainer.KeyControl) )) , - OperatorSessionKeyPermissions = _reflection.GeneratedProtocolMessageType('OperatorSessionKeyPermissions', (message.Message,), dict( + OperatorSessionKeyPermissions = _reflection.GeneratedProtocolMessageType('OperatorSessionKeyPermissions', (_message.Message,), dict( DESCRIPTOR = _LICENSE_KEYCONTAINER_OPERATORSESSIONKEYPERMISSIONS, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:License.KeyContainer.OperatorSessionKeyPermissions) )) , - VideoResolutionConstraint = _reflection.GeneratedProtocolMessageType('VideoResolutionConstraint', (message.Message,), dict( + VideoResolutionConstraint = _reflection.GeneratedProtocolMessageType('VideoResolutionConstraint', (_message.Message,), dict( DESCRIPTOR = _LICENSE_KEYCONTAINER_VIDEORESOLUTIONCONSTRAINT, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:License.KeyContainer.VideoResolutionConstraint) @@ -3632,32 +3632,32 @@ _sym_db.RegisterMessage(License.KeyContainer.KeyControl) _sym_db.RegisterMessage(License.KeyContainer.OperatorSessionKeyPermissions) _sym_db.RegisterMessage(License.KeyContainer.VideoResolutionConstraint) -LicenseError = _reflection.GeneratedProtocolMessageType('LicenseError', (message.Message,), dict( +LicenseError = _reflection.GeneratedProtocolMessageType('LicenseError', (_message.Message,), dict( DESCRIPTOR = _LICENSEERROR, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:LicenseError) )) _sym_db.RegisterMessage(LicenseError) -LicenseRequest = _reflection.GeneratedProtocolMessageType('LicenseRequest', (message.Message,), dict( +LicenseRequest = _reflection.GeneratedProtocolMessageType('LicenseRequest', (_message.Message,), dict( - ContentIdentification = _reflection.GeneratedProtocolMessageType('ContentIdentification', (message.Message,), dict( + ContentIdentification = _reflection.GeneratedProtocolMessageType('ContentIdentification', (_message.Message,), dict( - CENC = _reflection.GeneratedProtocolMessageType('CENC', (message.Message,), dict( + CENC = _reflection.GeneratedProtocolMessageType('CENC', (_message.Message,), dict( DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_CENC, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.CENC) )) , - WebM = _reflection.GeneratedProtocolMessageType('WebM', (message.Message,), dict( + WebM = _reflection.GeneratedProtocolMessageType('WebM', (_message.Message,), dict( DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_WEBM, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.WebM) )) , - ExistingLicense = _reflection.GeneratedProtocolMessageType('ExistingLicense', (message.Message,), dict( + ExistingLicense = _reflection.GeneratedProtocolMessageType('ExistingLicense', (_message.Message,), dict( DESCRIPTOR = _LICENSEREQUEST_CONTENTIDENTIFICATION_EXISTINGLICENSE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:LicenseRequest.ContentIdentification.ExistingLicense) @@ -3678,25 +3678,25 @@ _sym_db.RegisterMessage(LicenseRequest.ContentIdentification.CENC) _sym_db.RegisterMessage(LicenseRequest.ContentIdentification.WebM) _sym_db.RegisterMessage(LicenseRequest.ContentIdentification.ExistingLicense) -LicenseRequestRaw = _reflection.GeneratedProtocolMessageType('LicenseRequestRaw', (message.Message,), dict( +LicenseRequestRaw = _reflection.GeneratedProtocolMessageType('LicenseRequestRaw', (_message.Message,), dict( - ContentIdentification = _reflection.GeneratedProtocolMessageType('ContentIdentification', (message.Message,), dict( + ContentIdentification = _reflection.GeneratedProtocolMessageType('ContentIdentification', (_message.Message,), dict( - CENC = _reflection.GeneratedProtocolMessageType('CENC', (message.Message,), dict( + CENC = _reflection.GeneratedProtocolMessageType('CENC', (_message.Message,), dict( DESCRIPTOR = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_CENC, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:LicenseRequestRaw.ContentIdentification.CENC) )) , - WebM = _reflection.GeneratedProtocolMessageType('WebM', (message.Message,), dict( + WebM = _reflection.GeneratedProtocolMessageType('WebM', (_message.Message,), dict( DESCRIPTOR = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_WEBM, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:LicenseRequestRaw.ContentIdentification.WebM) )) , - ExistingLicense = _reflection.GeneratedProtocolMessageType('ExistingLicense', (message.Message,), dict( + ExistingLicense = _reflection.GeneratedProtocolMessageType('ExistingLicense', (_message.Message,), dict( DESCRIPTOR = _LICENSEREQUESTRAW_CONTENTIDENTIFICATION_EXISTINGLICENSE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:LicenseRequestRaw.ContentIdentification.ExistingLicense) @@ -3717,121 +3717,121 @@ _sym_db.RegisterMessage(LicenseRequestRaw.ContentIdentification.CENC) _sym_db.RegisterMessage(LicenseRequestRaw.ContentIdentification.WebM) _sym_db.RegisterMessage(LicenseRequestRaw.ContentIdentification.ExistingLicense) -ProvisionedDeviceInfo = _reflection.GeneratedProtocolMessageType('ProvisionedDeviceInfo', (message.Message,), dict( +ProvisionedDeviceInfo = _reflection.GeneratedProtocolMessageType('ProvisionedDeviceInfo', (_message.Message,), dict( DESCRIPTOR = _PROVISIONEDDEVICEINFO, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:ProvisionedDeviceInfo) )) _sym_db.RegisterMessage(ProvisionedDeviceInfo) -ProvisioningOptions = _reflection.GeneratedProtocolMessageType('ProvisioningOptions', (message.Message,), dict( +ProvisioningOptions = _reflection.GeneratedProtocolMessageType('ProvisioningOptions', (_message.Message,), dict( DESCRIPTOR = _PROVISIONINGOPTIONS, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:ProvisioningOptions) )) _sym_db.RegisterMessage(ProvisioningOptions) -ProvisioningRequest = _reflection.GeneratedProtocolMessageType('ProvisioningRequest', (message.Message,), dict( +ProvisioningRequest = _reflection.GeneratedProtocolMessageType('ProvisioningRequest', (_message.Message,), dict( DESCRIPTOR = _PROVISIONINGREQUEST, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:ProvisioningRequest) )) _sym_db.RegisterMessage(ProvisioningRequest) -ProvisioningResponse = _reflection.GeneratedProtocolMessageType('ProvisioningResponse', (message.Message,), dict( +ProvisioningResponse = _reflection.GeneratedProtocolMessageType('ProvisioningResponse', (_message.Message,), dict( DESCRIPTOR = _PROVISIONINGRESPONSE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:ProvisioningResponse) )) _sym_db.RegisterMessage(ProvisioningResponse) -RemoteAttestation = _reflection.GeneratedProtocolMessageType('RemoteAttestation', (message.Message,), dict( +RemoteAttestation = _reflection.GeneratedProtocolMessageType('RemoteAttestation', (_message.Message,), dict( DESCRIPTOR = _REMOTEATTESTATION, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:RemoteAttestation) )) _sym_db.RegisterMessage(RemoteAttestation) -SessionInit = _reflection.GeneratedProtocolMessageType('SessionInit', (message.Message,), dict( +SessionInit = _reflection.GeneratedProtocolMessageType('SessionInit', (_message.Message,), dict( DESCRIPTOR = _SESSIONINIT, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SessionInit) )) _sym_db.RegisterMessage(SessionInit) -SessionState = _reflection.GeneratedProtocolMessageType('SessionState', (message.Message,), dict( +SessionState = _reflection.GeneratedProtocolMessageType('SessionState', (_message.Message,), dict( DESCRIPTOR = _SESSIONSTATE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SessionState) )) _sym_db.RegisterMessage(SessionState) -SignedCertificateStatusList = _reflection.GeneratedProtocolMessageType('SignedCertificateStatusList', (message.Message,), dict( +SignedCertificateStatusList = _reflection.GeneratedProtocolMessageType('SignedCertificateStatusList', (_message.Message,), dict( DESCRIPTOR = _SIGNEDCERTIFICATESTATUSLIST, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SignedCertificateStatusList) )) _sym_db.RegisterMessage(SignedCertificateStatusList) -SignedDeviceCertificate = _reflection.GeneratedProtocolMessageType('SignedDeviceCertificate', (message.Message,), dict( +SignedDeviceCertificate = _reflection.GeneratedProtocolMessageType('SignedDeviceCertificate', (_message.Message,), dict( DESCRIPTOR = _SIGNEDDEVICECERTIFICATE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SignedDeviceCertificate) )) _sym_db.RegisterMessage(SignedDeviceCertificate) -SignedProvisioningMessage = _reflection.GeneratedProtocolMessageType('SignedProvisioningMessage', (message.Message,), dict( +SignedProvisioningMessage = _reflection.GeneratedProtocolMessageType('SignedProvisioningMessage', (_message.Message,), dict( DESCRIPTOR = _SIGNEDPROVISIONINGMESSAGE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SignedProvisioningMessage) )) _sym_db.RegisterMessage(SignedProvisioningMessage) -SignedMessage = _reflection.GeneratedProtocolMessageType('SignedMessage', (message.Message,), dict( +SignedMessage = _reflection.GeneratedProtocolMessageType('SignedMessage', (_message.Message,), dict( DESCRIPTOR = _SIGNEDMESSAGE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SignedMessage) )) _sym_db.RegisterMessage(SignedMessage) -WidevineCencHeader = _reflection.GeneratedProtocolMessageType('WidevineCencHeader', (message.Message,), dict( +WidevineCencHeader = _reflection.GeneratedProtocolMessageType('WidevineCencHeader', (_message.Message,), dict( DESCRIPTOR = _WIDEVINECENCHEADER, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:WidevineCencHeader) )) _sym_db.RegisterMessage(WidevineCencHeader) -SignedLicenseRequest = _reflection.GeneratedProtocolMessageType('SignedLicenseRequest', (message.Message,), dict( +SignedLicenseRequest = _reflection.GeneratedProtocolMessageType('SignedLicenseRequest', (_message.Message,), dict( DESCRIPTOR = _SIGNEDLICENSEREQUEST, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SignedLicenseRequest) )) _sym_db.RegisterMessage(SignedLicenseRequest) -SignedLicenseRequestRaw = _reflection.GeneratedProtocolMessageType('SignedLicenseRequestRaw', (message.Message,), dict( +SignedLicenseRequestRaw = _reflection.GeneratedProtocolMessageType('SignedLicenseRequestRaw', (_message.Message,), dict( DESCRIPTOR = _SIGNEDLICENSEREQUESTRAW, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SignedLicenseRequestRaw) )) _sym_db.RegisterMessage(SignedLicenseRequestRaw) -SignedLicense = _reflection.GeneratedProtocolMessageType('SignedLicense', (message.Message,), dict( +SignedLicense = _reflection.GeneratedProtocolMessageType('SignedLicense', (_message.Message,), dict( DESCRIPTOR = _SIGNEDLICENSE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SignedLicense) )) _sym_db.RegisterMessage(SignedLicense) -SignedServiceCertificate = _reflection.GeneratedProtocolMessageType('SignedServiceCertificate', (message.Message,), dict( +SignedServiceCertificate = _reflection.GeneratedProtocolMessageType('SignedServiceCertificate', (_message.Message,), dict( DESCRIPTOR = _SIGNEDSERVICECERTIFICATE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:SignedServiceCertificate) )) _sym_db.RegisterMessage(SignedServiceCertificate) -FileHashes = _reflection.GeneratedProtocolMessageType('FileHashes', (message.Message,), dict( +FileHashes = _reflection.GeneratedProtocolMessageType('FileHashes', (_message.Message,), dict( - Signature = _reflection.GeneratedProtocolMessageType('Signature', (message.Message,), dict( + Signature = _reflection.GeneratedProtocolMessageType('Signature', (_message.Message,), dict( DESCRIPTOR = _FILEHASHES_SIGNATURE, __module__ = 'widevine' # @@protoc_insertion_point(class_scope:FileHashes.Signature) diff --git a/vinetrimmer/utils/widevine/vmp.py b/vinetrimmer/utils/widevine/vmp.py index 9fbd125..9dfafb4 100644 --- a/vinetrimmer/utils/widevine/vmp.py +++ b/vinetrimmer/utils/widevine/vmp.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod try: # this was tested to work with protobuf 3, but it's an internal API (any varint decoder might work) - from protobuf3.internal.decoder import _DecodeVarint as _di + from google.protobuf.internal.decoder import _DecodeVarint as _di except ImportError: # this is generic and does not depend on pb internals, # however it will decode "larger" possible numbers than pb decoder which has them fixed diff --git a/vinetrimmer/vendor/pymp4/adapters.py b/vinetrimmer/vendor/pymp4/adapters.py new file mode 100644 index 0000000..6a4555c --- /dev/null +++ b/vinetrimmer/vendor/pymp4/adapters.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from abc import ABC +from uuid import UUID + +from construct import Adapter, int2byte + + +class ISO6392TLanguageCode(Adapter, ABC): + def _decode(self, obj, context, path): + return "".join([ + chr(bit + 0x60) + for bit in ( + (obj >> 10) & 0b11111, + (obj >> 5) & 0b11111, + obj & 0b11111 + ) + ]) + + def _encode(self, obj, context, path): + bits = [ord(c) - 0x60 for c in obj] + return (bits[0] << 10) | (bits[1] << 5) | bits[2] + + +class MaskedInteger(Adapter, ABC): + def _decode(self, obj, context, path): + return obj & 0x1F + + def _encode(self, obj, context, path): + return obj & 0x1F + + +class UUIDBytes(Adapter, ABC): + def _decode(self, obj, context, path): + return UUID(bytes=obj) + + def _encode(self, obj, context, path): + return obj.bytes diff --git a/vinetrimmer/vendor/pymp4/cli.py b/vinetrimmer/vendor/pymp4/cli.py index 426b8f6..4394812 100644 --- a/vinetrimmer/vendor/pymp4/cli.py +++ b/vinetrimmer/vendor/pymp4/cli.py @@ -1,14 +1,17 @@ #!/usr/bin/env python -from __future__ import print_function + import io import logging import argparse -from pymp4.parser import Box -from construct import setglobalfullprinting +from construct import setGlobalPrintPrivateEntries, setGlobalPrintFullStrings + +from .parser import Box log = logging.getLogger(__name__) -setglobalfullprinting(True) + +setGlobalPrintPrivateEntries(True) +setGlobalPrintFullStrings(False) def dump(): diff --git a/vinetrimmer/vendor/pymp4/parser.py b/vinetrimmer/vendor/pymp4/parser.py index e3ab8b2..f66db97 100644 --- a/vinetrimmer/vendor/pymp4/parser.py +++ b/vinetrimmer/vendor/pymp4/parser.py @@ -18,127 +18,59 @@ import logging from uuid import UUID from construct import * -import construct.core from construct.lib import * +from .adapters import ISO6392TLanguageCode, MaskedInteger, UUIDBytes +from .subconstructs import TellPlusSizeOf, TellMinusSizeOf + log = logging.getLogger(__name__) UNITY_MATRIX = [0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000] -class PrefixedIncludingSize(Subconstruct): - __slots__ = ["name", "lengthfield", "subcon"] - - def __init__(self, lengthfield, subcon): - super(PrefixedIncludingSize, self).__init__(subcon) - self.lengthfield = lengthfield - - def _parse(self, stream, context, path): - try: - lengthfield_size = self.lengthfield.sizeof() - length = self.lengthfield._parse(stream, context, path) - except SizeofError: - offset_start = stream.tell() - length = self.lengthfield._parse(stream, context, path) - lengthfield_size = stream.tell() - offset_start - - stream2 = BoundBytesIO(stream, length - lengthfield_size) - obj = self.subcon._parse(stream2, context, path) - return obj - - def _build(self, obj, stream, context, path): - try: - # needs to be both fixed size, seekable and tellable (third not checked) - self.lengthfield.sizeof() - if not stream.seekable: - raise SizeofError - offset_start = stream.tell() - self.lengthfield._build(0, stream, context, path) - self.subcon._build(obj, stream, context, path) - offset_end = stream.tell() - stream.seek(offset_start) - self.lengthfield._build(offset_end - offset_start, stream, context, path) - stream.seek(offset_end) - except SizeofError: - data = self.subcon.build(obj, context) - sl, p_sl = 0, 0 - dlen = len(data) - # do..while - i = 0 - while True: - i += 1 - p_sl = sl - sl = len(self.lengthfield.build(dlen + sl)) - if p_sl == sl: break - - self.lengthfield._build(dlen + sl, stream, context, path) - else: - self.lengthfield._build(len(data), stream, context, path) - construct.core._write_stream(stream, len(data), data) - - def _sizeof(self, context, path): - return self.lengthfield._sizeof(context, path) + self.subcon._sizeof(context, path) - - # Header box FileTypeBox = Struct( - "type" / Const(b"ftyp"), - "major_brand" / String(4), + "major_brand" / PaddedString(4, "ascii"), "minor_version" / Int32ub, - "compatible_brands" / GreedyRange(String(4)), + "compatible_brands" / GreedyRange(PaddedString(4, "ascii")), ) SegmentTypeBox = Struct( - "type" / Const(b"styp"), - "major_brand" / String(4), + "major_brand" / PaddedString(4, "ascii"), "minor_version" / Int32ub, - "compatible_brands" / GreedyRange(String(4)), + "compatible_brands" / GreedyRange(PaddedString(4, "ascii")), ) # Catch find boxes RawBox = Struct( - "type" / String(4, padchar=b" ", paddir="right"), "data" / Default(GreedyBytes, b"") ) FreeBox = Struct( - "type" / Const(b"free"), "data" / GreedyBytes ) SkipBox = Struct( - "type" / Const(b"skip"), "data" / GreedyBytes ) # Movie boxes, contained in a moov Box MovieHeaderBox = Struct( - "type" / Const(b"mvhd"), "version" / Default(Int8ub, 0), "flags" / Default(Int24ub, 0), - Embedded(Switch(this.version, { - 1: Struct( - "creation_time" / Default(Int64ub, 0), - "modification_time" / Default(Int64ub, 0), - "timescale" / Default(Int32ub, 10000000), - "duration" / Int64ub - ), - 0: Struct( - "creation_time" / Default(Int32ub, 0), - "modification_time" / Default(Int32ub, 0), - "timescale" / Default(Int32ub, 10000000), - "duration" / Int32ub, - ), - })), + "creation_time" / Default(Switch(this.version, {0: Int32ub, 1: Int64ub}), 0), + "modification_time" / Default(Switch(this.version, {0: Int32ub, 1: Int64ub}), 0), + "timescale" / Default(Int32ub, 10000000), + "duration" / Switch(this.version, {0: Int32ub, 1: Int64ub}), "rate" / Default(Int32sb, 65536), "volume" / Default(Int16sb, 256), # below could be just Padding(10) but why not - Const(Int16ub, 0), - Const(Int32ub, 0), - Const(Int32ub, 0), + Const(0, Int16ub), + Const(0, Int32ub), + Const(0, Int32ub), "matrix" / Default(Int32sb[9], UNITY_MATRIX), "pre_defined" / Default(Int32ub[6], [0] * 6), "next_track_ID" / Default(Int32ub, 0xffffffff) @@ -147,25 +79,13 @@ MovieHeaderBox = Struct( # Track boxes, contained in trak box TrackHeaderBox = Struct( - "type" / Const(b"tkhd"), "version" / Default(Int8ub, 0), "flags" / Default(Int24ub, 1), - Embedded(Switch(this.version, { - 1: Struct( - "creation_time" / Default(Int64ub, 0), - "modification_time" / Default(Int64ub, 0), - "track_ID" / Default(Int32ub, 1), - Padding(4), - "duration" / Default(Int64ub, 0), - ), - 0: Struct( - "creation_time" / Default(Int32ub, 0), - "modification_time" / Default(Int32ub, 0), - "track_ID" / Default(Int32ub, 1), - Padding(4), - "duration" / Default(Int32ub, 0), - ), - })), + "creation_time" / Default(Switch(this.version, {0: Int32ub, 1: Int64ub}), 0), + "modification_time" / Default(Switch(this.version, {0: Int32ub, 1: Int64ub}), 0), + "track_ID" / Default(Int32ub, 1), + Padding(4), + "duration" / Default(Switch(this.version, {0: Int32ub, 1: Int64ub}), 0), Padding(8), "layer" / Default(Int16sb, 0), "alternate_group" / Default(Int16sb, 0), @@ -177,11 +97,10 @@ TrackHeaderBox = Struct( ) HDSSegmentBox = Struct( - "type" / Const(b"abst"), "version" / Default(Int8ub, 0), "flags" / Default(Int24ub, 0), "info_version" / Int32ub, - EmbeddedBitStruct( + "flags" / BitStruct( Padding(1), "profile" / Flag, "live" / Flag, @@ -191,20 +110,19 @@ HDSSegmentBox = Struct( "time_scale" / Int32ub, "current_media_time" / Int64ub, "smpte_time_code_offset" / Int64ub, - "movie_identifier" / CString(), - "server_entry_table" / PrefixedArray(Int8ub, CString()), - "quality_entry_table" / PrefixedArray(Int8ub, CString()), - "drm_data" / CString(), - "metadata" / CString(), + "movie_identifier" / CString("ascii"), + "server_entry_table" / PrefixedArray(Int8ub, CString("ascii")), + "quality_entry_table" / PrefixedArray(Int8ub, CString("ascii")), + "drm_data" / CString("ascii"), + "metadata" / CString("ascii"), "segment_run_table" / PrefixedArray(Int8ub, LazyBound(lambda x: Box)), "fragment_run_table" / PrefixedArray(Int8ub, LazyBound(lambda x: Box)) ) HDSSegmentRunBox = Struct( - "type" / Const(b"asrt"), "version" / Default(Int8ub, 0), "flags" / Default(Int24ub, 0), - "quality_entry_table" / PrefixedArray(Int8ub, CString()), + "quality_entry_table" / PrefixedArray(Int8ub, CString("ascii")), "segment_run_enteries" / PrefixedArray(Int32ub, Struct( "first_segment" / Int32ub, "fragments_per_segment" / Int32ub @@ -212,14 +130,13 @@ HDSSegmentRunBox = Struct( ) HDSFragmentRunBox = Struct( - "type" / Const(b"afrt"), "version" / Default(Int8ub, 0), "flags" / BitStruct( Padding(23), "update" / Flag ), "time_scale" / Int32ub, - "quality_entry_table" / PrefixedArray(Int8ub, CString()), + "quality_entry_table" / PrefixedArray(Int8ub, CString("ascii")), "fragment_run_enteries" / PrefixedArray(Int32ub, Struct( "first_fragment" / Int32ub, "first_fragment_timestamp" / Int64ub, @@ -231,51 +148,31 @@ HDSFragmentRunBox = Struct( # Boxes contained by Media Box -class ISO6392TLanguageCode(Adapter): - def _decode(self, obj, context): - """ - Get the python representation of the obj - """ - return b''.join(map(int2byte, [c + 0x60 for c in bytearray(obj)])).decode("utf8") - - def _encode(self, obj, context): - """ - Get the bytes representation of the obj - """ - return [c - 0x60 for c in bytearray(obj.encode("utf8"))] - - MediaHeaderBox = Struct( - "type" / Const(b"mdhd"), "version" / Default(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "flags" / Const(0, Int24ub), "creation_time" / IfThenElse(this.version == 1, Int64ub, Int32ub), "modification_time" / IfThenElse(this.version == 1, Int64ub, Int32ub), "timescale" / Int32ub, "duration" / IfThenElse(this.version == 1, Int64ub, Int32ub), - Embedded(BitStruct( - Padding(1), - "language" / ISO6392TLanguageCode(BitsInteger(5)[3]), - )), - Padding(2, pattern=b"\x00"), + "language" / ISO6392TLanguageCode(Int16ub), + Padding(2, pattern=b"\x00") ) HandlerReferenceBox = Struct( - "type" / Const(b"hdlr"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), Padding(4, pattern=b"\x00"), - "handler_type" / String(4), + "handler_type" / PaddedString(4, "ascii"), Padding(12, pattern=b"\x00"), # Int32ub[3] - "name" / CString(encoding="utf8") + "name" / CString("utf8") ) # Boxes contained by Media Info Box VideoMediaHeaderBox = Struct( - "type" / Const(b"vmhd"), "version" / Default(Int8ub, 0), - "flags" / Const(Int24ub, 1), + "flags" / Const(1, Int24ub), "graphics_mode" / Default(Int16ub, 0), "opcolor" / Struct( "red" / Default(Int16ub, 0), @@ -284,71 +181,59 @@ VideoMediaHeaderBox = Struct( ), ) -DataEntryUrlBox = PrefixedIncludingSize(Int32ub, Struct( - "type" / Const(b"url "), - "version" / Const(Int8ub, 0), +DataEntryUrlBox = Struct( + "version" / Const(0, Int8ub), "flags" / BitStruct( Padding(23), "self_contained" / Rebuild(Flag, ~this._.location) ), - "location" / If(~this.flags.self_contained, CString(encoding="utf8")), -)) + "location" / If(~this.flags.self_contained, CString("utf8")), +) -DataEntryUrnBox = PrefixedIncludingSize(Int32ub, Struct( - "type" / Const(b"urn "), - "version" / Const(Int8ub, 0), +DataEntryUrnBox = Struct( + "version" / Const(0, Int8ub), "flags" / BitStruct( Padding(23), "self_contained" / Rebuild(Flag, ~(this._.name & this._.location)) ), - "name" / If(this.flags == 0, CString(encoding="utf8")), - "location" / If(this.flags == 0, CString(encoding="utf8")), -)) + "name" / If(this.flags == 0, CString("utf8")), + "location" / If(this.flags == 0, CString("utf8")), +) DataReferenceBox = Struct( - "type" / Const(b"dref"), - "version" / Const(Int8ub, 0), + "version" / Const(0, Int8ub), "flags" / Default(Int24ub, 0), - "data_entries" / PrefixedArray(Int32ub, Select(DataEntryUrnBox, DataEntryUrlBox)), + "data_entries" / PrefixedArray(Int32ub, LazyBound(lambda: Box)), ) # Sample Table boxes (stbl) MP4ASampleEntryBox = Struct( "version" / Default(Int16ub, 0), - "revision" / Const(Int16ub, 0), - "vendor" / Const(Int32ub, 0), + "revision" / Const(0, Int16ub), + "vendor" / Const(0, Int32ub), "channels" / Default(Int16ub, 2), "bits_per_sample" / Default(Int16ub, 16), "compression_id" / Default(Int16sb, 0), - "packet_size" / Const(Int16ub, 0), + "packet_size" / Const(0, Int16ub), "sampling_rate" / Int16ub, Padding(2) ) - -class MaskedInteger(Adapter): - def _decode(self, obj, context): - return obj & 0x1F - - def _encode(self, obj, context): - return obj & 0x1F - - AAVC = Struct( - "version" / Const(Int8ub, 1), + "version" / Const(1, Int8ub), "profile" / Int8ub, "compatibility" / Int8ub, "level" / Int8ub, - EmbeddedBitStruct( + "flags" / BitStruct( Padding(6, pattern=b'\x01'), "nal_unit_length_field" / Default(BitsInteger(2), 3), ), - "sps" / Default(PrefixedArray(MaskedInteger(Int8ub), PascalString(Int16ub)), []), - "pps" / Default(PrefixedArray(Int8ub, PascalString(Int16ub)), []) + "sps" / Default(PrefixedArray(MaskedInteger(Int8ub), PascalString(Int16ub, "ascii")), []), + "pps" / Default(PrefixedArray(Int8ub, PascalString(Int16ub, "ascii")), []) ) HVCC = Struct( - EmbeddedBitStruct( - "version" / Const(BitsInteger(8), 1), + "version" / Const(1, Int8ub), + "flags" / BitStruct( "profile_space" / BitsInteger(2), "general_tier_flag" / BitsInteger(1), "general_profile" / BitsInteger(5), @@ -377,8 +262,8 @@ HVCC = Struct( AVC1SampleEntryBox = Struct( "version" / Default(Int16ub, 0), - "revision" / Const(Int16ub, 0), - "vendor" / Default(String(4, padchar=b" "), b"brdy"), + "revision" / Const(0, Int16ub), + "vendor" / Default(PaddedString(4, "ascii"), "brdy"), "temporal_quality" / Default(Int32ub, 0), "spatial_quality" / Default(Int32ub, 0), "width" / Int16ub, @@ -387,62 +272,58 @@ AVC1SampleEntryBox = Struct( Padding(2), "vertical_resolution" / Default(Int16ub, 72), # TODO: actually a fixed point decimal Padding(2), - "data_size" / Const(Int32ub, 0), + "data_size" / Const(0, Int32ub), "frame_count" / Default(Int16ub, 1), - "compressor_name" / Default(String(32, padchar=b" "), ""), + "compressor_name" / Default(PaddedString(32, "ascii"), None), "depth" / Default(Int16ub, 24), "color_table_id" / Default(Int16sb, -1), - "avc_data" / PrefixedIncludingSize(Int32ub, Struct( - "type" / String(4, padchar=b" ", paddir="right"), - Embedded(Switch(this.type, { - b"avcC": AAVC, - b"hvcC": HVCC, - }, Struct("data" / GreedyBytes))) - )), + "avc_data" / Prefixed(Int32ub, Struct( + "type" / PaddedString(4, "ascii"), + "data" / Switch(this.type, { + "avcC": AAVC, + "hvcC": HVCC, + }, GreedyBytes) + ), includelength=True), "sample_info" / LazyBound(lambda _: GreedyRange(Box)) ) -SampleEntryBox = PrefixedIncludingSize(Int32ub, Struct( - "format" / String(4, padchar=b" ", paddir="right"), +SampleEntryBox = Prefixed(Int32ub, Struct( + "format" / PaddedString(4, "ascii"), Padding(6, pattern=b"\x00"), "data_reference_index" / Default(Int16ub, 1), - Embedded(Switch(this.format, { - b"ec-3": MP4ASampleEntryBox, - b"mp4a": MP4ASampleEntryBox, - b"enca": MP4ASampleEntryBox, - b"avc1": AVC1SampleEntryBox, - b"encv": AVC1SampleEntryBox, - b"wvtt": Struct("children" / LazyBound(lambda ctx: GreedyRange(Box))) - }, Struct("data" / GreedyBytes))) -)) + "data" / Switch(this.format, { + "ec-3": MP4ASampleEntryBox, + "mp4a": MP4ASampleEntryBox, + "enca": MP4ASampleEntryBox, + "avc1": AVC1SampleEntryBox, + "encv": AVC1SampleEntryBox, + "wvtt": Struct("children" / LazyBound(lambda: GreedyRange(Box))) + }, GreedyBytes) +), includelength=True) BitRateBox = Struct( - "type" / Const(b"btrt"), "bufferSizeDB" / Int32ub, "maxBitrate" / Int32ub, "avgBirate" / Int32ub, ) SampleDescriptionBox = Struct( - "type" / Const(b"stsd"), "version" / Default(Int8ub, 0), - "flags" / Const(Int24ub, 0), - "entries" / PrefixedArray(Int32ub, SampleEntryBox) + "flags" / Const(0, Int24ub), + "entries" / PrefixedArray(Int32ub, LazyBound(lambda: Box)) ) SampleSizeBox = Struct( - "type" / Const(b"stsz"), "version" / Int8ub, - "flags" / Const(Int24ub, 0), + "flags" / Const(0, Int24ub), "sample_size" / Int32ub, "sample_count" / Int32ub, "entry_sizes" / If(this.sample_size == 0, Array(this.sample_count, Int32ub)) ) SampleSizeBox2 = Struct( - "type" / Const(b"stz2"), "version" / Int8ub, - "flags" / Const(Int24ub, 0), + "flags" / Const(0, Int24ub), Padding(3, pattern=b"\x00"), "field_size" / Int8ub, "sample_count" / Int24ub, @@ -452,15 +333,13 @@ SampleSizeBox2 = Struct( ) SampleDegradationPriorityBox = Struct( - "type" / Const(b"stdp"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), ) TimeToSampleBox = Struct( - "type" / Const(b"stts"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), "entries" / Default(PrefixedArray(Int32ub, Struct( "sample_count" / Int32ub, "sample_delta" / Int32ub, @@ -468,18 +347,31 @@ TimeToSampleBox = Struct( ) SyncSampleBox = Struct( - "type" / Const(b"stss"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), "entries" / Default(PrefixedArray(Int32ub, Struct( "sample_number" / Int32ub, )), []) ) +CompositionOffsetBox = Struct( + "version" / Default(Int8ub, 0), + "flags" / Const(0, Int24ub), + "entries" / Switch(this.version, { + 0: Default(PrefixedArray(Int32ub, Struct( + "sample_count" / Int32ub, + "sample_offset" / Int32ub, + )), []), + 1: Default(PrefixedArray(Int32ub, Struct( + "sample_count" / Int32ub, + "sample_offset" / Int32sb, + )), []) + }) +) + SampleToChunkBox = Struct( - "type" / Const(b"stsc"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), "entries" / Default(PrefixedArray(Int32ub, Struct( "first_chunk" / Int32ub, "samples_per_chunk" / Int32ub, @@ -488,18 +380,16 @@ SampleToChunkBox = Struct( ) ChunkOffsetBox = Struct( - "type" / Const(b"stco"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), "entries" / Default(PrefixedArray(Int32ub, Struct( "chunk_offset" / Int32ub, )), []) ) ChunkLargeOffsetBox = Struct( - "type" / Const(b"co64"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), "entries" / PrefixedArray(Int32ub, Struct( "chunk_offset" / Int64ub, )) @@ -508,16 +398,14 @@ ChunkLargeOffsetBox = Struct( # Movie Fragment boxes, contained in moof box MovieFragmentHeaderBox = Struct( - "type" / Const(b"mfhd"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), "sequence_number" / Int32ub ) TrackFragmentBaseMediaDecodeTimeBox = Struct( - "type" / Const(b"tfdt"), "version" / Int8ub, - "flags" / Const(Int24ub, 0), + "flags" / Const(0, Int24ub), "baseMediaDecodeTime" / Switch(this.version, {1: Int64ub, 0: Int32ub}) ) @@ -533,7 +421,6 @@ TrackSampleFlags = BitStruct( ) TrackRunBox = Struct( - "type" / Const(b"trun"), "version" / Int8ub, "flags" / BitStruct( Padding(12), @@ -561,7 +448,6 @@ TrackRunBox = Struct( ) TrackFragmentHeaderBox = Struct( - "type" / Const(b"tfhd"), "version" / Int8ub, "flags" / BitStruct( Padding(6), @@ -584,18 +470,16 @@ TrackFragmentHeaderBox = Struct( ) MovieExtendsHeaderBox = Struct( - "type" / Const(b"mehd"), "version" / Default(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "flags" / Const(0, Int24ub), "fragment_duration" / IfThenElse(this.version == 1, Default(Int64ub, 0), Default(Int32ub, 0)) ) TrackExtendsBox = Struct( - "type" / Const(b"trex"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), "track_ID" / Int32ub, "default_sample_description_index" / Default(Int32ub, 1), "default_sample_duration" / Default(Int32ub, 0), @@ -604,9 +488,8 @@ TrackExtendsBox = Struct( ) SegmentIndexBox = Struct( - "type" / Const(b"sidx"), "version" / Int8ub, - "flags" / Const(Int24ub, 0), + "flags" / Const(0, Int24ub), "reference_ID" / Int32ub, "timescale" / Int32ub, "earliest_presentation_time" / IfThenElse(this.version == 0, Int32ub, Int64ub), @@ -624,8 +507,7 @@ SegmentIndexBox = Struct( ) SampleAuxiliaryInformationSizesBox = Struct( - "type" / Const(b"saiz"), - "version" / Const(Int8ub, 0), + "version" / Const(0, Int8ub), "flags" / BitStruct( Padding(23), "has_aux_info_type" / Flag, @@ -641,7 +523,6 @@ SampleAuxiliaryInformationSizesBox = Struct( ) SampleAuxiliaryInformationOffsetsBox = Struct( - "type" / Const(b"saio"), "version" / Int8ub, "flags" / BitStruct( Padding(23), @@ -657,35 +538,24 @@ SampleAuxiliaryInformationOffsetsBox = Struct( # Movie data box MovieDataBox = Struct( - "type" / Const(b"mdat"), "data" / GreedyBytes ) # Media Info Box SoundMediaHeaderBox = Struct( - "type" / Const(b"smhd"), - "version" / Const(Int8ub, 0), - "flags" / Const(Int24ub, 0), + "version" / Const(0, Int8ub), + "flags" / Const(0, Int24ub), "balance" / Default(Int16sb, 0), - "reserved" / Const(Int16ub, 0) + "reserved" / Const(0, Int16ub) ) # DASH Boxes -class UUIDBytes(Adapter): - def _decode(self, obj, context): - return UUID(bytes=obj) - - def _encode(self, obj, context): - return obj.bytes - - ProtectionSystemHeaderBox = Struct( - "type" / If(this._.type != b"uuid", Const(b"pssh")), "version" / Rebuild(Int8ub, lambda ctx: 1 if (hasattr(ctx, "key_IDs") and ctx.key_IDs) else 0), - "flags" / Const(Int24ub, 0), + "flags" / Const(0, Int24ub), "system_ID" / UUIDBytes(Bytes(16)), "key_IDs" / Default(If(this.version == 1, PrefixedArray(Int32ub, UUIDBytes(Bytes(16)))), @@ -694,10 +564,9 @@ ProtectionSystemHeaderBox = Struct( ) TrackEncryptionBox = Struct( - "type" / If(this._.type != b"uuid", Const(b"tenc")), "version" / Default(OneOf(Int8ub, (0, 1)), 0), "flags" / Default(Int24ub, 0), - "_reserved" / Const(Int8ub, 0), + "_reserved" / Const(0, Int8ub), "default_byte_blocks" / Default(IfThenElse( this.version > 0, BitStruct( @@ -706,7 +575,7 @@ TrackEncryptionBox = Struct( # count of unencrypted blocks in the protection pattern "skip" / Nibble ), - Const(Int8ub, 0) + Const(0, Int8ub) ), 0), "is_encrypted" / OneOf(Int8ub, (0, 1)), "iv_size" / OneOf(Int8ub, (0, 8, 16)), @@ -718,8 +587,7 @@ TrackEncryptionBox = Struct( ) SampleEncryptionBox = Struct( - "type" / If(this._.type != b"uuid", Const(b"senc")), - "version" / Const(Int8ub, 0), + "version" / Const(0, Int8ub), "flags" / BitStruct( Padding(22), "has_subsample_encryption_info" / Flag, @@ -736,21 +604,18 @@ SampleEncryptionBox = Struct( ) OriginalFormatBox = Struct( - "type" / Const(b"frma"), - "original_format" / Default(String(4), b"avc1") + "original_format" / Default(PaddedString(4, "ascii"), "avc1") ) SchemeTypeBox = Struct( - "type" / Const(b"schm"), "version" / Default(Int8ub, 0), "flags" / Default(Int24ub, 0), - "scheme_type" / Default(String(4), b"cenc"), + "scheme_type" / Default(PaddedString(4, "ascii"), "cenc"), "scheme_version" / Default(Int32ub, 0x00010000), - "schema_uri" / Default(If(this.flags & 1 == 1, CString()), None) + "schema_uri" / Default(If(this.flags & 1 == 1, CString("ascii")), None) ) ProtectionSchemeInformationBox = Struct( - "type" / Const(b"sinf"), # TODO: define which children are required 'schm', 'schi' and 'tenc' "children" / LazyBound(lambda _: GreedyRange(Box)) ) @@ -758,7 +623,6 @@ ProtectionSchemeInformationBox = Struct( # PIFF boxes UUIDBox = Struct( - "type" / Const(b"uuid"), "extended_type" / UUIDBytes(Bytes(16)), "data" / Switch(this.extended_type, { UUID("A2394F52-5A9B-4F14-A244-6C427C648DF4"): SampleEncryptionBox, @@ -770,119 +634,102 @@ UUIDBox = Struct( # WebVTT boxes CueIDBox = Struct( - "type" / Const(b"iden"), "cue_id" / GreedyString("utf8") ) CueSettingsBox = Struct( - "type" / Const(b"sttg"), "settings" / GreedyString("utf8") ) CuePayloadBox = Struct( - "type" / Const(b"payl"), "cue_text" / GreedyString("utf8") ) WebVTTConfigurationBox = Struct( - "type" / Const(b"vttC"), "config" / GreedyString("utf8") ) WebVTTSourceLabelBox = Struct( - "type" / Const(b"vlab"), "label" / GreedyString("utf8") ) -ContainerBoxLazy = LazyBound(lambda ctx: ContainerBox) +ContainerBoxLazy = LazyBound(lambda: ContainerBox) -class TellMinusSizeOf(Subconstruct): - def __init__(self, subcon): - super(TellMinusSizeOf, self).__init__(subcon) - self.flagbuildnone = True - - def _parse(self, stream, context, path): - return stream.tell() - self.subcon.sizeof(context) - - def _build(self, obj, stream, context, path): - return b"" - - def sizeof(self, context=None, **kw): - return 0 - - -Box = PrefixedIncludingSize(Int32ub, Struct( +Box = Prefixed(Int32ub, Struct( "offset" / TellMinusSizeOf(Int32ub), - "type" / Peek(String(4, padchar=b" ", paddir="right")), - Embedded(Switch(this.type, { - b"ftyp": FileTypeBox, - b"styp": SegmentTypeBox, - b"mvhd": MovieHeaderBox, - b"moov": ContainerBoxLazy, - b"moof": ContainerBoxLazy, - b"mfhd": MovieFragmentHeaderBox, - b"tfdt": TrackFragmentBaseMediaDecodeTimeBox, - b"trun": TrackRunBox, - b"tfhd": TrackFragmentHeaderBox, - b"traf": ContainerBoxLazy, - b"mvex": ContainerBoxLazy, - b"mehd": MovieExtendsHeaderBox, - b"trex": TrackExtendsBox, - b"trak": ContainerBoxLazy, - b"mdia": ContainerBoxLazy, - b"tkhd": TrackHeaderBox, - b"mdat": MovieDataBox, - b"free": FreeBox, - b"skip": SkipBox, - b"mdhd": MediaHeaderBox, - b"hdlr": HandlerReferenceBox, - b"minf": ContainerBoxLazy, - b"vmhd": VideoMediaHeaderBox, - b"dinf": ContainerBoxLazy, - b"dref": DataReferenceBox, - b"stbl": ContainerBoxLazy, - b"stsd": SampleDescriptionBox, - b"stsz": SampleSizeBox, - b"stz2": SampleSizeBox2, - b"stts": TimeToSampleBox, - b"stss": SyncSampleBox, - b"stsc": SampleToChunkBox, - b"stco": ChunkOffsetBox, - b"co64": ChunkLargeOffsetBox, - b"smhd": SoundMediaHeaderBox, - b"sidx": SegmentIndexBox, - b"saiz": SampleAuxiliaryInformationSizesBox, - b"saio": SampleAuxiliaryInformationOffsetsBox, - b"btrt": BitRateBox, + "type" / PaddedString(4, "ascii"), + "data" / Switch(this.type, { + "ftyp": FileTypeBox, + "styp": SegmentTypeBox, + "mvhd": MovieHeaderBox, + "moov": ContainerBoxLazy, + "moof": ContainerBoxLazy, + "mfhd": MovieFragmentHeaderBox, + "tfdt": TrackFragmentBaseMediaDecodeTimeBox, + "trun": TrackRunBox, + "tfhd": TrackFragmentHeaderBox, + "traf": ContainerBoxLazy, + "mvex": ContainerBoxLazy, + "mehd": MovieExtendsHeaderBox, + "trex": TrackExtendsBox, + "trak": ContainerBoxLazy, + "edts": ContainerBoxLazy, + "mdia": ContainerBoxLazy, + "tkhd": TrackHeaderBox, + "mdat": MovieDataBox, + "free": FreeBox, + "skip": SkipBox, + "mdhd": MediaHeaderBox, + "hdlr": HandlerReferenceBox, + "minf": ContainerBoxLazy, + "vmhd": VideoMediaHeaderBox, + "dinf": ContainerBoxLazy, + "dref": DataReferenceBox, + "url ": DataEntryUrlBox, + "urn ": DataEntryUrnBox, + "stbl": ContainerBoxLazy, + "stsd": SampleDescriptionBox, + "stsz": SampleSizeBox, + "stz2": SampleSizeBox2, + "stts": TimeToSampleBox, + "stss": SyncSampleBox, + "ctts": CompositionOffsetBox, + "stsc": SampleToChunkBox, + "stco": ChunkOffsetBox, + "co64": ChunkLargeOffsetBox, + "smhd": SoundMediaHeaderBox, + "sidx": SegmentIndexBox, + "saiz": SampleAuxiliaryInformationSizesBox, + "saio": SampleAuxiliaryInformationOffsetsBox, + "btrt": BitRateBox, # dash - b"tenc": TrackEncryptionBox, - b"pssh": ProtectionSystemHeaderBox, - b"senc": SampleEncryptionBox, - b"sinf": ProtectionSchemeInformationBox, - b"frma": OriginalFormatBox, - b"schm": SchemeTypeBox, - b"schi": ContainerBoxLazy, + "tenc": TrackEncryptionBox, + "pssh": ProtectionSystemHeaderBox, + "senc": SampleEncryptionBox, + "sinf": ProtectionSchemeInformationBox, + "frma": OriginalFormatBox, + "schm": SchemeTypeBox, + "schi": ContainerBoxLazy, # piff - b"uuid": UUIDBox, + "uuid": UUIDBox, # HDS boxes - b'abst': HDSSegmentBox, - b'asrt': HDSSegmentRunBox, - b'afrt': HDSFragmentRunBox, + "abst": HDSSegmentBox, + "asrt": HDSSegmentRunBox, + "afrt": HDSFragmentRunBox, # WebVTT - b"vttC": WebVTTConfigurationBox, - b"vlab": WebVTTSourceLabelBox, - b"vttc": ContainerBoxLazy, - b"vttx": ContainerBoxLazy, - b"iden": CueIDBox, - b"sttg": CueSettingsBox, - b"payl": CuePayloadBox - }, default=RawBox)), - "end" / Tell -)) + "vttC": WebVTTConfigurationBox, + "vlab": WebVTTSourceLabelBox, + "vttc": ContainerBoxLazy, + "vttx": ContainerBoxLazy, + "iden": CueIDBox, + "sttg": CueSettingsBox, + "payl": CuePayloadBox + }, default=RawBox), + "end" / TellPlusSizeOf(Int32ub) +), includelength=True) ContainerBox = Struct( - "type" / String(4, padchar=b" ", paddir="right"), "children" / GreedyRange(Box) ) diff --git a/vinetrimmer/vendor/pymp4/subconstructs.py b/vinetrimmer/vendor/pymp4/subconstructs.py new file mode 100644 index 0000000..1701b49 --- /dev/null +++ b/vinetrimmer/vendor/pymp4/subconstructs.py @@ -0,0 +1,32 @@ +from abc import ABC + +from construct import Subconstruct + + +class TellPlusSizeOf(Subconstruct, ABC): + def __init__(self, subcon): + super(TellPlusSizeOf, self).__init__(subcon) + self.flagbuildnone = True + + def _parse(self, stream, context, path): + return stream.tell() + self.subcon.sizeof(context=context) + + def _build(self, obj, stream, context, path): + return b"" + + def sizeof(self, context=None, **kw): + return 0 + +class TellMinusSizeOf(Subconstruct, ABC): + def __init__(self, subcon): + super(TellMinusSizeOf, self).__init__(subcon) + self.flagbuildnone = True + + def _parse(self, stream, context, path): + return stream.tell() - self.subcon.sizeof(context=context) + + def _build(self, obj, stream, context, path): + return b"" + + def sizeof(self, context=None, **kw): + return 0 diff --git a/vinetrimmer/vendor/pymp4/util.py b/vinetrimmer/vendor/pymp4/util.py index 73a3eb8..58a6611 100644 --- a/vinetrimmer/vendor/pymp4/util.py +++ b/vinetrimmer/vendor/pymp4/util.py @@ -17,7 +17,7 @@ """ import logging -from pymp4.exceptions import BoxNotFound +from .exceptions import BoxNotFound log = logging.getLogger(__name__) diff --git a/vinetrimmer/vinetrimmer.py b/vinetrimmer/vinetrimmer.py index d31f166..80fe7b4 100644 --- a/vinetrimmer/vinetrimmer.py +++ b/vinetrimmer/vinetrimmer.py @@ -71,8 +71,6 @@ def main(debug): dl() -# D:\PlayReady-Amazon-Tool-main\.venv\Scripts\python.exe -X pycache_prefix=C:\Users\Aswin\AppData\Local\JetBrains\PyCharm2024.3\cpython-cache "C:/Program Files (x86)/JetBrains/PyCharm 2024.2.4/plugins/python-ce/helpers/pydev/pydevd.py" --port 42000 --module --multiprocess --save-signatures --qt-support=auto --file poetry run vt dl --no-cache --keys AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 -# Above seems to work + if __name__ == "__main__": - #sys.argv = ["vinetrimmer", "dl", "--no-cache", "--keys", "AMZN", "0H7LY5ZKKBM1MIW0244WE9O2C4"] main() diff --git a/vinetrimmer/vinetrimmer.yml b/vinetrimmer/vinetrimmer.yml index 38918e5..e15642d 100644 --- a/vinetrimmer/vinetrimmer.yml +++ b/vinetrimmer/vinetrimmer.yml @@ -7,20 +7,22 @@ aria2c: cdm: - default: 'hisense_smarttv_he55a7000euwts_sl3000' - Amazon: 'hisense_smarttv_he55a7000euwts_sl3000' + default: 'samsung_electronics_co_ltd_sm-t710_eur_open_sm-t710_sl2000' + Amazon: 'samsung_electronics_co_ltd_sm-t710_eur_open_sm-t710_sl2000' + AppleTVPlus: 'hisense_smarttv_hu50a6100uw_sl3000' cdm_api: - - name: 'playready' - host: 'http://api.drmlab.io/prvinetrimmer' - key: 'MKBsQ04VbRkq0sMzPKoT5hnOazeH7rOA' - device: 'pr3k' + - name: 'amazon' + host: 'http://31.207.45.191:62318' + username: '4ppl' + key: '1256521d4f83411192b923b9f71dd26' + device: 'j4' type: 'PLAYREADY' - system_id: 3000 + system_id: 12345 security_level: 1 credentials: - iTunes: 'Playreadydrm@proton.me' + iTunes: '' directories: temp: '' diff --git a/vinetrimmer1.py b/vinetrimmer1.py deleted file mode 100644 index d31f166..0000000 --- a/vinetrimmer1.py +++ /dev/null @@ -1,78 +0,0 @@ -import logging -import os -import sys -from datetime import datetime - -import click -import coloredlogs - -from vinetrimmer.config import directories, filenames # isort: split -from vinetrimmer.commands import dl - - -@click.command(context_settings=dict( - allow_extra_args=True, - ignore_unknown_options=True, - max_content_width=116, # max PEP8 line-width, -4 to adjust for initial indent -)) -@click.option("--debug", is_flag=True, default=False, - help="Enable DEBUG level logs on the console. This is always enabled for log files.") -def main(debug): - """ - vinetrimmer is the most convenient command-line program to - download videos from Widevine DRM-protected video platforms. - """ - LOG_FORMAT = "{asctime} [{levelname[0]}] {name} : {message}" - LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" - LOG_STYLE = "{" - - def log_exit(self, msg, *args, **kwargs): - self.critical(msg, *args, **kwargs) - sys.exit(1) - - logging.Logger.exit = log_exit - - os.makedirs(directories.logs, exist_ok=True) - logging.basicConfig( - level=logging.DEBUG, - format=LOG_FORMAT, - datefmt=LOG_DATE_FORMAT, - style=LOG_STYLE, - handlers=[logging.FileHandler( - os.path.join(directories.logs, filenames.log.format(time=datetime.now().strftime("%Y%m%d-%H%M%S"))), - encoding='utf-8' - )] - ) - - coloredlogs.install( - level=logging.DEBUG if debug else logging.INFO, - fmt=LOG_FORMAT, - datefmt=LOG_DATE_FORMAT, - style=LOG_STYLE, - handlers=[logging.StreamHandler()], - ) - - log = logging.getLogger("vt") - - log.info("vinetrimmer - Widevine DRM downloader and decrypter") - log.info(f"[Root Config] : {filenames.user_root_config}") - log.info(f"[Service Configs] : {directories.service_configs}") - log.info(f"[Cookies] : {directories.cookies}") - log.info(f"[CDM Devices] : {directories.devices}") - log.info(f"[Cache] : {directories.cache}") - log.info(f"[Logs] : {directories.logs}") - log.info(f"[Temp Files] : {directories.temp}") - log.info(f"[Downloads] : {directories.downloads}") - - os.environ['PATH'] = os.path.abspath('./binaries') - - if len(sys.argv) > 1 and sys.argv[1].lower() == "dl": - sys.argv.pop(1) - - dl() - -# D:\PlayReady-Amazon-Tool-main\.venv\Scripts\python.exe -X pycache_prefix=C:\Users\Aswin\AppData\Local\JetBrains\PyCharm2024.3\cpython-cache "C:/Program Files (x86)/JetBrains/PyCharm 2024.2.4/plugins/python-ce/helpers/pydev/pydevd.py" --port 42000 --module --multiprocess --save-signatures --qt-support=auto --file poetry run vt dl --no-cache --keys AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 -# Above seems to work -if __name__ == "__main__": - #sys.argv = ["vinetrimmer", "dl", "--no-cache", "--keys", "AMZN", "0H7LY5ZKKBM1MIW0244WE9O2C4"] - main() diff --git a/vt.py b/vt.py deleted file mode 100644 index d31f166..0000000 --- a/vt.py +++ /dev/null @@ -1,78 +0,0 @@ -import logging -import os -import sys -from datetime import datetime - -import click -import coloredlogs - -from vinetrimmer.config import directories, filenames # isort: split -from vinetrimmer.commands import dl - - -@click.command(context_settings=dict( - allow_extra_args=True, - ignore_unknown_options=True, - max_content_width=116, # max PEP8 line-width, -4 to adjust for initial indent -)) -@click.option("--debug", is_flag=True, default=False, - help="Enable DEBUG level logs on the console. This is always enabled for log files.") -def main(debug): - """ - vinetrimmer is the most convenient command-line program to - download videos from Widevine DRM-protected video platforms. - """ - LOG_FORMAT = "{asctime} [{levelname[0]}] {name} : {message}" - LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" - LOG_STYLE = "{" - - def log_exit(self, msg, *args, **kwargs): - self.critical(msg, *args, **kwargs) - sys.exit(1) - - logging.Logger.exit = log_exit - - os.makedirs(directories.logs, exist_ok=True) - logging.basicConfig( - level=logging.DEBUG, - format=LOG_FORMAT, - datefmt=LOG_DATE_FORMAT, - style=LOG_STYLE, - handlers=[logging.FileHandler( - os.path.join(directories.logs, filenames.log.format(time=datetime.now().strftime("%Y%m%d-%H%M%S"))), - encoding='utf-8' - )] - ) - - coloredlogs.install( - level=logging.DEBUG if debug else logging.INFO, - fmt=LOG_FORMAT, - datefmt=LOG_DATE_FORMAT, - style=LOG_STYLE, - handlers=[logging.StreamHandler()], - ) - - log = logging.getLogger("vt") - - log.info("vinetrimmer - Widevine DRM downloader and decrypter") - log.info(f"[Root Config] : {filenames.user_root_config}") - log.info(f"[Service Configs] : {directories.service_configs}") - log.info(f"[Cookies] : {directories.cookies}") - log.info(f"[CDM Devices] : {directories.devices}") - log.info(f"[Cache] : {directories.cache}") - log.info(f"[Logs] : {directories.logs}") - log.info(f"[Temp Files] : {directories.temp}") - log.info(f"[Downloads] : {directories.downloads}") - - os.environ['PATH'] = os.path.abspath('./binaries') - - if len(sys.argv) > 1 and sys.argv[1].lower() == "dl": - sys.argv.pop(1) - - dl() - -# D:\PlayReady-Amazon-Tool-main\.venv\Scripts\python.exe -X pycache_prefix=C:\Users\Aswin\AppData\Local\JetBrains\PyCharm2024.3\cpython-cache "C:/Program Files (x86)/JetBrains/PyCharm 2024.2.4/plugins/python-ce/helpers/pydev/pydevd.py" --port 42000 --module --multiprocess --save-signatures --qt-support=auto --file poetry run vt dl --no-cache --keys AMZN 0H7LY5ZKKBM1MIW0244WE9O2C4 -# Above seems to work -if __name__ == "__main__": - #sys.argv = ["vinetrimmer", "dl", "--no-cache", "--keys", "AMZN", "0H7LY5ZKKBM1MIW0244WE9O2C4"] - main()