diff --git a/src/Microsoft.ComponentDetection.Common/FileUtilityService.cs b/src/Microsoft.ComponentDetection.Common/FileUtilityService.cs index ec4805cb2..e9a89699c 100644 --- a/src/Microsoft.ComponentDetection.Common/FileUtilityService.cs +++ b/src/Microsoft.ComponentDetection.Common/FileUtilityService.cs @@ -1,6 +1,7 @@ namespace Microsoft.ComponentDetection.Common; using System.IO; +using System.Threading.Tasks; using Microsoft.ComponentDetection.Contracts; /// @@ -18,6 +19,12 @@ public string ReadAllText(FileInfo file) return File.ReadAllText(file.FullName); } + /// + public async Task ReadAllTextAsync(FileInfo file) + { + return await File.ReadAllTextAsync(file.FullName); + } + /// public bool Exists(string fileName) { diff --git a/src/Microsoft.ComponentDetection.Common/PathUtilityService.cs b/src/Microsoft.ComponentDetection.Common/PathUtilityService.cs index f5c1307bb..484b6870d 100644 --- a/src/Microsoft.ComponentDetection.Common/PathUtilityService.cs +++ b/src/Microsoft.ComponentDetection.Common/PathUtilityService.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Common; +namespace Microsoft.ComponentDetection.Common; using System; using System.IO; @@ -75,4 +75,7 @@ public string ResolvePhysicalPath(string path) } private string ResolvePathFromInfo(FileSystemInfo info) => info.LinkTarget ?? info.FullName; + + public string NormalizePath(string path) => + path?.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar); } diff --git a/src/Microsoft.ComponentDetection.Common/Telemetry/Records/FailedParsingFileRecord.cs b/src/Microsoft.ComponentDetection.Common/Telemetry/Records/FailedParsingFileRecord.cs new file mode 100644 index 000000000..6dc532119 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Common/Telemetry/Records/FailedParsingFileRecord.cs @@ -0,0 +1,14 @@ +namespace Microsoft.ComponentDetection.Common.Telemetry.Records; + +public class FailedParsingFileRecord : BaseDetectionTelemetryRecord +{ + public override string RecordName => "FailedParsingFile"; + + public string DetectorId { get; set; } + + public string FilePath { get; set; } + + public string ExceptionMessage { get; set; } + + public string StackTrace { get; set; } +} diff --git a/src/Microsoft.ComponentDetection.Common/Telemetry/Records/FailedReadingFileRecord.cs b/src/Microsoft.ComponentDetection.Common/Telemetry/Records/FailedReadingFileRecord.cs deleted file mode 100644 index b7490a0c4..000000000 --- a/src/Microsoft.ComponentDetection.Common/Telemetry/Records/FailedReadingFileRecord.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Microsoft.ComponentDetection.Common.Telemetry.Records; - -public class FailedReadingFileRecord : BaseDetectionTelemetryRecord -{ - public override string RecordName => "FailedReadingFile"; - - public string FilePath { get; set; } - - public string ExceptionMessage { get; set; } - - public string StackTrace { get; set; } -} diff --git a/src/Microsoft.ComponentDetection.Common/Telemetry/Records/PipReportFailureTelemetryRecord.cs b/src/Microsoft.ComponentDetection.Common/Telemetry/Records/PipReportFailureTelemetryRecord.cs new file mode 100644 index 000000000..3f2a72d58 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Common/Telemetry/Records/PipReportFailureTelemetryRecord.cs @@ -0,0 +1,10 @@ +namespace Microsoft.ComponentDetection.Common.Telemetry.Records; + +public class PipReportFailureTelemetryRecord : BaseDetectionTelemetryRecord +{ + public override string RecordName => "PipReportFailure"; + + public int ExitCode { get; set; } + + public string StdErr { get; set; } +} diff --git a/src/Microsoft.ComponentDetection.Common/Telemetry/Records/PipReportVersionTelemetryRecord.cs b/src/Microsoft.ComponentDetection.Common/Telemetry/Records/PipReportVersionTelemetryRecord.cs new file mode 100644 index 000000000..26242d459 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Common/Telemetry/Records/PipReportVersionTelemetryRecord.cs @@ -0,0 +1,10 @@ +namespace Microsoft.ComponentDetection.Common.Telemetry.Records; + +public class PipReportVersionTelemetryRecord : BaseDetectionTelemetryRecord +{ + public override string RecordName => "PipReportVersion"; + + public string Version { get; set; } + + public string MaxVersion { get; set; } +} diff --git a/src/Microsoft.ComponentDetection.Contracts/IFileUtilityService.cs b/src/Microsoft.ComponentDetection.Contracts/IFileUtilityService.cs index 0a7cceded..a76c1ca61 100644 --- a/src/Microsoft.ComponentDetection.Contracts/IFileUtilityService.cs +++ b/src/Microsoft.ComponentDetection.Contracts/IFileUtilityService.cs @@ -1,6 +1,7 @@ -namespace Microsoft.ComponentDetection.Contracts; +namespace Microsoft.ComponentDetection.Contracts; using System.IO; +using System.Threading.Tasks; /// /// Wraps some common file operations for easier testability. This interface is *only used by the command line driven app*. @@ -21,6 +22,13 @@ public interface IFileUtilityService /// Returns a string of the file contents. string ReadAllText(FileInfo file); + /// + /// Returns the contents of the file. + /// + /// File to read. + /// Returns a string of the file contents. + Task ReadAllTextAsync(FileInfo file); + /// /// Returns true if the file exists. /// diff --git a/src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs b/src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs index 339a02461..ff7fe467f 100644 --- a/src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs +++ b/src/Microsoft.ComponentDetection.Contracts/IPathUtilityService.cs @@ -1,4 +1,4 @@ -namespace Microsoft.ComponentDetection.Contracts; +namespace Microsoft.ComponentDetection.Contracts; /// /// Wraps some common folder operations, shared across command line app and service. @@ -34,4 +34,11 @@ public interface IPathUtilityService /// File name without directory. /// Returns true if file name matches a pattern, otherwise false. bool MatchesPattern(string searchPattern, string fileName); + + /// + /// Normalizes the path to the system based separator. + /// + /// the path. + /// normalized path. + string NormalizePath(string path); } diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/IPipCommandService.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/IPipCommandService.cs new file mode 100644 index 000000000..5392866d6 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/IPipCommandService.cs @@ -0,0 +1,30 @@ +namespace Microsoft.ComponentDetection.Detectors.Pip; + +using System; +using System.IO; +using System.Threading.Tasks; + +public interface IPipCommandService +{ + /// + /// Checks the existence of pip. + /// + /// Optional override of the pip.exe absolute path. + /// True if pip is found on the OS PATH. + Task PipExistsAsync(string pipPath = null); + + /// + /// Retrieves the version of pip from the given path. PythonVersion allows for loose version strings such as "1". + /// + /// Optional override of the pip.exe absolute path. + /// Version of pip. + Task GetPipVersionAsync(string pipPath = null); + + /// + /// Generates a pip installation report for a given setup.py or requirements.txt file. + /// + /// Path of the Python requirements file. + /// Optional override of the pip.exe absolute path. + /// See https://pip.pypa.io/en/stable/reference/installation-report/#specification. + Task<(PipInstallationReport Report, FileInfo ReportFile)> GenerateInstallationReportAsync(string path, string pipExePath = null); +} diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/IPythonCommandService.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/IPythonCommandService.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/IPythonCommandService.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/IPythonCommandService.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/IPythonResolver.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/IPythonResolver.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/IPythonResolver.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/IPythonResolver.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/ISimplePyPiClient.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/ISimplePyPiClient.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/ISimplePyPiClient.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/ISimplePyPiClient.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/ISimplePythonResolver.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/ISimplePythonResolver.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/ISimplePythonResolver.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/ISimplePythonResolver.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PipDependencySpecification.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipDependencySpecification.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/PipDependencySpecification.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipDependencySpecification.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PipGraphNode.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipGraphNode.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/PipGraphNode.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipGraphNode.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationMetadata.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationMetadata.cs new file mode 100644 index 000000000..0b14bfb71 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationMetadata.cs @@ -0,0 +1,79 @@ +namespace Microsoft.ComponentDetection.Detectors.Pip; + +using Newtonsoft.Json; + +/// +/// Metadata for a pip component being installed. See https://packaging.python.org/en/latest/specifications/core-metadata/. +/// Some fields are not collected here because they are not needed for dependency graph construction. +/// +public sealed record PipInstallationMetadata +{ + /// + /// Version of the file format; legal values are "1.0", "1.1", "1.2", "2.1", "2.2", and "2.3" + /// as of May 2024. + /// + [JsonProperty("metadata_version")] + public string MetadataVersion { get; set; } + + /// + /// The name of the distribution. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// A string containing the distribution’s version number. + /// + [JsonProperty("version")] + public string Version { get; set; } + + /// + /// Each entry contains a string naming some other distutils project required by this distribution. + /// See https://peps.python.org/pep-0508/ for the format of the strings. + /// + [JsonProperty("requires_dist")] + public string[] RequiresDist { get; set; } + + /// + /// URL for the distribution’s home page. + /// + [JsonProperty("home_page")] + public string HomePage { get; set; } + + /// + /// Maintainer’s name at a minimum; additional contact information may be provided. + /// + [JsonProperty("maintainer")] + public string Maintainer { get; set; } + + /// + /// Maintainer’s e-mail address. It can contain a name and e-mail address in the legal forms for a RFC-822 From: header. + /// + [JsonProperty("maintainer_email")] + public string MaintainerEmail { get; set; } + + /// + /// Author’s name at a minimum; additional contact information may be provided. + /// + [JsonProperty("author")] + public string Author { get; set; } + + /// + /// Author’s e-mail address. It can contain a name and e-mail address in the legal forms for a RFC-822 From: header. + /// + [JsonProperty("author_email")] + public string AuthorEmail { get; set; } + + /// + /// Text indicating the license covering the distribution. + /// + [JsonProperty("license")] + public string License { get; set; } + + /// + /// Each entry is a string giving a single classification value for the distribution. + /// Classifiers are described in PEP 301 https://peps.python.org/pep-0301/. + /// + [JsonProperty("classifier")] + public string[] Classifier { get; set; } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationReport.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationReport.cs new file mode 100644 index 000000000..480fa6a78 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationReport.cs @@ -0,0 +1,34 @@ +namespace Microsoft.ComponentDetection.Detectors.Pip; + +using System.Collections.Generic; +using Newtonsoft.Json; + +/// +/// See https://pip.pypa.io/en/stable/reference/installation-report/#specification. +/// +public sealed record PipInstallationReport +{ + /// + /// Version of the installation report specification. Currently 1, but will be incremented if the format changes. + /// + [JsonProperty("version")] + public string Version { get; set; } + + /// + /// Version of pip used to produce the report. + /// + [JsonProperty("pip_version")] + public string PipVersion { get; set; } + + /// + /// Distribution packages (to be) installed. + /// + [JsonProperty("install")] + public PipInstallationReportItem[] InstallItems { get; set; } + + /// + /// Environment metadata for the report. See https://peps.python.org/pep-0508/#environment-markers. + /// + [JsonProperty("environment")] + public IDictionary Environment { get; set; } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationReportItem.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationReportItem.cs new file mode 100644 index 000000000..ed4a7c0bb --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipInstallationReportItem.cs @@ -0,0 +1,45 @@ +namespace Microsoft.ComponentDetection.Detectors.Pip; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +public sealed record PipInstallationReportItem +{ + /// + /// The metadata of the distribution. + /// + [JsonProperty("metadata")] + public PipInstallationMetadata Metadata { get; set; } + + /// + /// true if the requirement was provided as, or constrained to, a direct URL reference. false if the requirements was provided as a name and version specifier. + /// + [JsonProperty("is_direct")] + public bool IsDirect { get; set; } + + /// + /// true if the requirement was yanked from the index, but was still selected by pip conform. + /// + [JsonProperty("is_yanked")] + public bool IsYanked { get; set; } + + /// + /// true if the requirement was explicitly provided by the user, either directly via + /// a command line argument or indirectly via a requirements file. false if the requirement + /// was installed as a dependency of another requirement. + /// + [JsonProperty("requested")] + public bool Requested { get; set; } + + /// + /// See https://packaging.python.org/en/latest/specifications/direct-url-data-structure/. + /// + [JsonProperty("download_info")] + public JObject DownloadInfo { get; set; } + + /// + /// Extras requested by the user. + /// + [JsonProperty("requested_extras")] + public JObject RequestedExtras { get; set; } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipReportGraphNode.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipReportGraphNode.cs new file mode 100644 index 000000000..8b689000a --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PipReportGraphNode.cs @@ -0,0 +1,25 @@ +namespace Microsoft.ComponentDetection.Detectors.Pip; + +using System.Collections.Generic; +using Microsoft.ComponentDetection.Contracts.TypedComponent; + +/// +/// Internal state used by PipReportDetector to hold intermediate structure info until the final +/// combination of dependencies and relationships is determined and can be returned. +/// +public sealed record PipReportGraphNode +{ + public PipReportGraphNode(PipComponent value, bool requested) + { + this.Value = value; + this.Requested = requested; + } + + public PipComponent Value { get; set; } + + public List Children { get; } = new List(); + + public List Parents { get; } = new List(); + + public bool Requested { get; set; } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonProject.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonProject.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/PythonProject.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonProject.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonProjectInfo.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonProjectInfo.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/PythonProjectInfo.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonProjectInfo.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonProjectRelease.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonProjectRelease.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/PythonProjectRelease.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonProjectRelease.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonResolverState.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonResolverState.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/PythonResolverState.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonResolverState.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonVersion.cs b/src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonVersion.cs similarity index 100% rename from src/Microsoft.ComponentDetection.Detectors/pip/PythonVersion.cs rename to src/Microsoft.ComponentDetection.Detectors/pip/Contracts/PythonVersion.cs diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PipCommandService.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PipCommandService.cs new file mode 100644 index 000000000..74c89ec59 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PipCommandService.cs @@ -0,0 +1,152 @@ +namespace Microsoft.ComponentDetection.Detectors.Pip; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Microsoft.ComponentDetection.Common.Telemetry.Records; +using Microsoft.ComponentDetection.Contracts; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +public class PipCommandService : IPipCommandService +{ + private readonly ICommandLineInvocationService commandLineInvocationService; + private readonly IPathUtilityService pathUtilityService; + private readonly IFileUtilityService fileUtilityService; + private readonly IEnvironmentVariableService environmentService; + private readonly ILogger logger; + + public PipCommandService() + { + } + + public PipCommandService( + ICommandLineInvocationService commandLineInvocationService, + IPathUtilityService pathUtilityService, + IFileUtilityService fileUtilityService, + IEnvironmentVariableService environmentService, + ILogger logger) + { + this.commandLineInvocationService = commandLineInvocationService; + this.pathUtilityService = pathUtilityService; + this.fileUtilityService = fileUtilityService; + this.environmentService = environmentService; + this.logger = logger; + } + + public async Task PipExistsAsync(string pipPath = null) + { + return !string.IsNullOrEmpty(await this.ResolvePipAsync(pipPath)); + } + + public async Task GetPipVersionAsync(string pipPath = null) + { + var pipExecutable = await this.ResolvePipAsync(pipPath); + var command = await this.commandLineInvocationService.ExecuteCommandAsync( + pipExecutable, + null, + "--version"); + + if (command.ExitCode != 0) + { + this.logger.LogDebug("Failed to execute pip version with StdErr {StdErr}.", command.StdErr); + return null; + } + + try + { + // stdout will be in the format of "pip 20.0.2 from c:\python\lib\site-packages\pip (python 3.8)" + var versionString = command.StdOut.Split(' ')[1]; + return Version.Parse(versionString); + } + catch (Exception) + { + this.logger.LogDebug("Failed to parse pip version with StdErr {StdErr}.", command.StdErr); + return null; + } + } + + private async Task ResolvePipAsync(string pipPath = null) + { + var pipCommand = string.IsNullOrEmpty(pipPath) ? "pip" : pipPath; + + if (await this.CanCommandBeLocatedAsync(pipCommand)) + { + return pipCommand; + } + + return null; + } + + private async Task CanCommandBeLocatedAsync(string pipPath) + { + return await this.commandLineInvocationService.CanCommandBeLocatedAsync(pipPath, new List { "pip3" }, "--version"); + } + + public async Task<(PipInstallationReport Report, FileInfo ReportFile)> GenerateInstallationReportAsync(string path, string pipExePath = null) + { + if (string.IsNullOrEmpty(path)) + { + return (new PipInstallationReport(), null); + } + + var pipExecutable = await this.ResolvePipAsync(pipExePath); + var formattedPath = this.pathUtilityService.NormalizePath(path); + var workingDir = new DirectoryInfo(this.pathUtilityService.GetParentDirectory(formattedPath)); + + CommandLineExecutionResult command; + var reportName = Path.GetRandomFileName(); + var reportFile = new FileInfo(Path.Combine(workingDir.FullName, reportName)); + + string pipReportCommand; + if (path.EndsWith(".py")) + { + pipReportCommand = $"install -e ."; + } + else if (path.EndsWith(".txt")) + { + pipReportCommand = "install -r requirements.txt"; + } + else + { + // Failure case, but this shouldn't be hit since detection is only running + // on setup.py and requirements.txt files. + this.logger.LogDebug("PipReport: Unsupported file type for pip installation report: {Path}", path); + return (new PipInstallationReport(), null); + } + + // When PIP_INDEX_URL is set, we need to pass it as a parameter to pip install command. + // This should be done before running detection by the build system, otherwise the detection + // will default to the public PyPI index if not configured in pip defaults. + pipReportCommand += $" --dry-run --ignore-installed --quiet --report {reportName}"; + if (this.environmentService.DoesEnvironmentVariableExist("PIP_INDEX_URL")) + { + pipReportCommand += $" --index-url {this.environmentService.GetEnvironmentVariable("PIP_INDEX_URL")}"; + } + + this.logger.LogDebug("PipReport: Generating pip installation report for {Path} with command: {Command}", formattedPath, pipReportCommand); + command = await this.commandLineInvocationService.ExecuteCommandAsync( + pipExecutable, + null, + workingDir, + pipReportCommand); + + if (command.ExitCode != 0) + { + this.logger.LogWarning("PipReport: Failed to generate pip installation report for file {Path} with exit code {ExitCode}", path, command.ExitCode); + this.logger.LogDebug("PipReport: Pip installation report error: {StdErr}", command.StdErr); + + using var failureRecord = new PipReportFailureTelemetryRecord + { + ExitCode = command.ExitCode, + StdErr = command.StdErr, + }; + + return (new PipInstallationReport(), null); + } + + var reportOutput = await this.fileUtilityService.ReadAllTextAsync(reportFile); + return (JsonConvert.DeserializeObject(reportOutput), reportFile); + } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PipReportComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PipReportComponentDetector.cs new file mode 100644 index 000000000..a07149b1f --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PipReportComponentDetector.cs @@ -0,0 +1,262 @@ +namespace Microsoft.ComponentDetection.Detectors.Pip; + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Microsoft.ComponentDetection.Common.Telemetry.Records; +using Microsoft.ComponentDetection.Contracts; +using Microsoft.ComponentDetection.Contracts.Internal; +using Microsoft.ComponentDetection.Contracts.TypedComponent; +using Microsoft.Extensions.Logging; + +public class PipReportComponentDetector : FileComponentDetector, IExperimentalDetector +{ + /// + /// The maximum version of the report specification that this detector can handle. + /// + private static readonly Version MaxReportVersion = new(1, 0, 0); + + /// + /// The minimum version of the pip utility that this detector can handle. + /// + private static readonly Version MinimumPipVersion = new(22, 2, 0); + + private readonly IPipCommandService pipCommandService; + + public PipReportComponentDetector( + IComponentStreamEnumerableFactory componentStreamEnumerableFactory, + IObservableDirectoryWalkerFactory walkerFactory, + IPipCommandService pipCommandService, + ILogger logger) + { + this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory; + this.Scanner = walkerFactory; + this.pipCommandService = pipCommandService; + this.Logger = logger; + } + + public override string Id => "PipReport"; + + public override IList SearchPatterns => new List { "setup.py", "requirements.txt" }; + + public override IEnumerable Categories => new List { "Python" }; + + public override IEnumerable SupportedComponentTypes { get; } = new[] { ComponentType.Pip }; + + public override int Version { get; } = 1; + + protected override async Task> OnPrepareDetectionAsync(IObservable processRequests, IDictionary detectorArgs) + { + this.CurrentScanRequest.DetectorArgs.TryGetValue("Pip.PipExePath", out var pipExePath); + if (!await this.pipCommandService.PipExistsAsync(pipExePath)) + { + this.Logger.LogInformation($"PipReport: No pip found on system. Pip installation report detection will not run."); + + return Enumerable.Empty().ToObservable(); + } + + var pipVersion = await this.pipCommandService.GetPipVersionAsync(pipExePath); + if (pipVersion is null || pipVersion < MinimumPipVersion) + { + this.Logger.LogInformation( + "PipReport: No valid pip version found on system. {MinimumPipVersion} or greater is required. Pip installation report detection will not run.", + MinimumPipVersion); + + return Enumerable.Empty().ToObservable(); + } + + return processRequests; + } + + protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary detectorArgs) + { + this.CurrentScanRequest.DetectorArgs.TryGetValue("Pip.PipExePath", out var pipExePath); + var singleFileComponentRecorder = processRequest.SingleFileComponentRecorder; + var file = processRequest.ComponentStream; + + FileInfo reportFile = null; + try + { + var stopwatch = Stopwatch.StartNew(); + this.Logger.LogInformation("PipReport: Generating pip installation report for {File}", file.Location); + + // Call pip executable to generate the installation report of a given project file. + (var report, reportFile) = await this.pipCommandService.GenerateInstallationReportAsync(file.Location, pipExePath); + + // The report version is used to determine how to parse the report. If it is greater + // than the maximum supported version, there may be new fields and the parsing will fail. + if (!int.TryParse(report.Version, out var reportVersion) || reportVersion > MaxReportVersion.Major) + { + this.Logger.LogWarning( + "PipReport: The pip installation report version {ReportVersion} is not supported. The maximum supported version is {MaxVersion}.", + report.Version, + MaxReportVersion); + + using var versionRecord = new PipReportVersionTelemetryRecord + { + Version = report.Version, + MaxVersion = MaxReportVersion.ToString(), + }; + + return; + } + + stopwatch.Stop(); + this.Logger.LogInformation( + "PipReport: Generating pip installation report for {File} completed in {TotalSeconds} seconds with {PkgCount} detected packages.", + file.Location, + stopwatch.ElapsedMilliseconds / 1000.0, + report.InstallItems?.Length ?? 0); + + // Now that all installed packages are known, we can build a graph of the dependencies. + if (report.InstallItems is not null) + { + var graph = this.BuildGraphFromInstallationReport(report); + this.RecordComponents(singleFileComponentRecorder, graph); + } + } + catch (Exception e) + { + this.Logger.LogError(e, "PipReport: Failure while parsing pip installation report for {File}", file.Location); + + using var parseFailedRecord = new FailedParsingFileRecord + { + DetectorId = this.Id, + FilePath = file.Location, + ExceptionMessage = e.Message, + StackTrace = e.StackTrace, + }; + + throw; + } + finally + { + // Clean up the report output JSON file so it isn't left on the machine. + if (reportFile is not null && reportFile.Exists) + { + reportFile.Delete(); + } + } + } + + private Dictionary BuildGraphFromInstallationReport(PipInstallationReport report) + { + // The installation report contains a list of all installed packages, including their dependencies. + // However, dependencies do not have explicitly marked root packages so we will need to build the + // graph ourselves using the requires_dist field. + var dependenciesByPkg = new Dictionary>(StringComparer.OrdinalIgnoreCase); + var nodeReferences = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var package in report.InstallItems) + { + // Normalize the package name to ensure consistency between the package name and the graph nodes. + var normalizedPkgName = PipReportUtilities.NormalizePackageNameFormat(package.Metadata.Name); + + var node = new PipReportGraphNode( + new PipComponent( + normalizedPkgName, + package.Metadata.Version, + author: PipReportUtilities.GetSupplierFromInstalledItem(package), + license: PipReportUtilities.GetLicenseFromInstalledItem(package)), + package.Requested); + + nodeReferences.Add(normalizedPkgName, node); + + // requires_dist will contain information about the dependencies of the package. + // However, we don't have PipReportGraphNodes for all dependencies, so we will use + // an intermediate layer to store the relationships and update the graph later. + if (package.Metadata?.RequiresDist is null) + { + continue; + } + + foreach (var dependency in package.Metadata.RequiresDist) + { + // Dependency strings can be in the form of: + // cffi (>=1.12) + // futures; python_version <= \"2.7\" + // sphinx (!=1.8.0,!=3.1.0,!=3.1.1,>=1.6.5) ; extra == 'docs' + var dependencySpec = new PipDependencySpecification($"Requires-Dist: {dependency}", requiresDist: true); + if (dependencySpec.PackageIsUnsafe()) + { + continue; + } + + if (dependenciesByPkg.ContainsKey(normalizedPkgName)) + { + dependenciesByPkg[normalizedPkgName].Add(dependencySpec); + } + else + { + dependenciesByPkg.Add(normalizedPkgName, new List { dependencySpec }); + } + } + } + + // Update the graph with their dependency relationships. + foreach (var dependency in dependenciesByPkg) + { + var rootNode = nodeReferences[dependency.Key]; + + // Update the "root" dependency. + foreach (var child in dependency.Value) + { + var normalizedChildName = PipReportUtilities.NormalizePackageNameFormat(child.Name); + + if (!nodeReferences.ContainsKey(normalizedChildName)) + { + // This dependency is not in the report, so we can't add it to the graph. + // Known potential causes: python_version/sys_platform specification. + continue; + } + + var childNode = nodeReferences[normalizedChildName]; + rootNode.Children.Add(childNode); + + // Add the link to the parent dependency. + childNode.Parents.Add(rootNode); + } + } + + return nodeReferences; + } + + private void RecordComponents( + ISingleFileComponentRecorder recorder, + Dictionary graph) + { + // Explicit root packages are marked with a requested flag. + // Parent components must be registered before their children. + foreach (var node in graph.Values) + { + var component = new DetectedComponent(node.Value); + recorder.RegisterUsage( + component, + isExplicitReferencedDependency: node.Requested); + } + + // Once the graph has been populated with all dependencies, we can register the relationships. + // Ideally this would happen in the same loop as the previous one, but we need to ensure that + // parentComponentId is guaranteed to exist in the graph or an exception will be thrown. + foreach (var node in graph.Values) + { + if (!node.Parents.Any()) + { + continue; + } + + var component = new DetectedComponent(node.Value); + foreach (var parent in node.Parents) + { + recorder.RegisterUsage( + component, + isExplicitReferencedDependency: node.Requested, + parentComponentId: parent.Value.Id); + } + } + } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PipReportUtilities.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PipReportUtilities.cs new file mode 100644 index 000000000..ca87e5cf5 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PipReportUtilities.cs @@ -0,0 +1,71 @@ +namespace Microsoft.ComponentDetection.Detectors.Pip; + +using System.Linq; +using System.Text.RegularExpressions; + +internal class PipReportUtilities +{ + private const int MaxLicenseFieldLength = 100; + private const string ClassifierFieldSeparator = " :: "; + private const string ClassifierFieldLicensePrefix = "License"; + + /// + /// Normalize the package name format to the standard Python Packaging format. + /// See https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization. + /// + /// + /// The name lowercased with all runs of the characters ., -, or _ + /// replaced with a single - character. + /// +#pragma warning disable CA1308 // Format requires lowercase. + public static string NormalizePackageNameFormat(string packageName) => + Regex.Replace(packageName, @"[-_.]+", "-").ToLowerInvariant(); +#pragma warning restore CA1308 + + public static string GetSupplierFromInstalledItem(PipInstallationReportItem component) + { + if (!string.IsNullOrWhiteSpace(component.Metadata?.Maintainer)) + { + return component.Metadata.Maintainer; + } + + if (!string.IsNullOrWhiteSpace(component.Metadata?.MaintainerEmail)) + { + return component.Metadata.MaintainerEmail; + } + + if (!string.IsNullOrWhiteSpace(component.Metadata?.Author)) + { + return component.Metadata.Author; + } + + if (!string.IsNullOrWhiteSpace(component.Metadata?.AuthorEmail)) + { + return component.Metadata.AuthorEmail; + } + + // If none of the fields are populated, return null. + return null; + } + + public static string GetLicenseFromInstalledItem(PipInstallationReportItem component) + { + // There are cases where the actual license text is found in the license field so we limit the length of this field to 100 characters. + if (component.Metadata?.License is not null && component.Metadata?.License.Length < MaxLicenseFieldLength) + { + return component.Metadata.License; + } + + if (component.Metadata?.Classifier is not null) + { + var licenseClassifiers = component.Metadata.Classifier.Where(x => !string.IsNullOrWhiteSpace(x) && x.StartsWith(ClassifierFieldLicensePrefix)); + + // Split the license classifiers by the " :: " and take the last part of the string + licenseClassifiers = licenseClassifiers.Select(x => x.Split(ClassifierFieldSeparator).Last()).ToList(); + + return string.Join(", ", licenseClassifiers); + } + + return null; + } +} diff --git a/src/Microsoft.ComponentDetection.Detectors/pip/PythonCommandService.cs b/src/Microsoft.ComponentDetection.Detectors/pip/PythonCommandService.cs index 16f5f13a6..a60bacb09 100644 --- a/src/Microsoft.ComponentDetection.Detectors/pip/PythonCommandService.cs +++ b/src/Microsoft.ComponentDetection.Detectors/pip/PythonCommandService.cs @@ -8,17 +8,27 @@ namespace Microsoft.ComponentDetection.Detectors.Pip; using System.Threading.Tasks; using Microsoft.ComponentDetection.Contracts; using Microsoft.ComponentDetection.Contracts.TypedComponent; +using Microsoft.Extensions.Logging; public class PythonCommandService : IPythonCommandService { private readonly ICommandLineInvocationService commandLineInvocationService; + private readonly IPathUtilityService pathUtilityService; + private readonly ILogger logger; public PythonCommandService() { } - public PythonCommandService(ICommandLineInvocationService commandLineInvocationService) => + public PythonCommandService( + ICommandLineInvocationService commandLineInvocationService, + IPathUtilityService pathUtilityService, + ILogger logger) + { this.commandLineInvocationService = commandLineInvocationService; + this.pathUtilityService = pathUtilityService; + this.logger = logger; + } public async Task PythonExistsAsync(string pythonPath = null) { @@ -57,12 +67,20 @@ private async Task> ParseSetupPyFileAsync(string filePath, string throw new PythonNotFoundException(); } + var formattedFilePath = this.pathUtilityService.NormalizePath(filePath); + var workingDir = this.pathUtilityService.GetParentDirectory(formattedFilePath); + // This calls out to python and prints out an array like: [ packageA, packageB, packageC ] // We need to have python interpret this file because install_requires can be composed at runtime - var command = await this.commandLineInvocationService.ExecuteCommandAsync(pythonExecutable, null, $"-c \"import distutils.core; setup=distutils.core.run_setup('{filePath.Replace('\\', '/')}'); print(setup.install_requires)\""); + var command = await this.commandLineInvocationService.ExecuteCommandAsync( + pythonExecutable, + null, + new DirectoryInfo(workingDir), + $"-c \"import distutils.core; setup=distutils.core.run_setup('{formattedFilePath}'); print(setup.install_requires)\""); if (command.ExitCode != 0) { + this.logger.LogDebug("Python: Failed distutils setup with error: {StdErr}", command.StdErr); return new List(); } diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Configs/PipReportExperiment.cs b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Configs/PipReportExperiment.cs new file mode 100644 index 000000000..27efde329 --- /dev/null +++ b/src/Microsoft.ComponentDetection.Orchestrator/Experiments/Configs/PipReportExperiment.cs @@ -0,0 +1,18 @@ +namespace Microsoft.ComponentDetection.Orchestrator.Experiments.Configs; + +using Microsoft.ComponentDetection.Contracts; +using Microsoft.ComponentDetection.Detectors.Pip; + +/// +/// Validating the . +/// +public class PipReportExperiment : IExperimentConfiguration +{ + public string Name => "PipReport"; + + public bool IsInControlGroup(IComponentDetector componentDetector) => componentDetector is PipComponentDetector; + + public bool IsInExperimentGroup(IComponentDetector componentDetector) => componentDetector is PipReportComponentDetector; + + public bool ShouldRecord(IComponentDetector componentDetector, int numComponents) => true; +} diff --git a/src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs b/src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs index 5cf5dad10..e819f515e 100644 --- a/src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs +++ b/src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs @@ -65,6 +65,7 @@ public static IServiceCollection AddComponentDetection(this IServiceCollection s services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // Detectors // CocoaPods @@ -116,6 +117,8 @@ public static IServiceCollection AddComponentDetection(this IServiceCollection s services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); // pnpm services.AddSingleton(); diff --git a/test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs b/test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs new file mode 100644 index 000000000..12704e7c0 --- /dev/null +++ b/test/Microsoft.ComponentDetection.Common.Tests/PathUtilityServiceTests.cs @@ -0,0 +1,29 @@ +namespace Microsoft.ComponentDetection.Common.Tests; + +using System.IO; +using FluentAssertions; +using Microsoft.ComponentDetection.Common; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +[TestCategory("Governance/All")] +[TestCategory("Governance/ComponentDetection")] +public class PathUtilityServiceTests +{ + [TestMethod] + public void PathShouldBeNormalized() + { + var service = new PathUtilityService(new NullLogger()); + var path = "Users\\SomeUser\\someDir\\someFile"; + var normalizedPath = service.NormalizePath(path); + if (Path.DirectorySeparatorChar == '\\') + { + normalizedPath.Should().Be(path); + } + else + { + normalizedPath.Should().Be(string.Join(Path.DirectorySeparatorChar, path.Split('\\'))); + } + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/Microsoft.ComponentDetection.Detectors.Tests.csproj b/test/Microsoft.ComponentDetection.Detectors.Tests/Microsoft.ComponentDetection.Detectors.Tests.csproj index f85097c66..eeb1b1c8b 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/Microsoft.ComponentDetection.Detectors.Tests.csproj +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/Microsoft.ComponentDetection.Detectors.Tests.csproj @@ -11,6 +11,7 @@ + @@ -33,6 +34,18 @@ Always + + Always + + + Always + + + Always + + + Always + diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/TestResources.Designer.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/TestResources.Designer.cs index dc3c690ed..35906f3c7 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/TestResources.Designer.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/TestResources.Designer.cs @@ -1,183 +1,266 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.ComponentDetection.Detectors.Tests.Mocks { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class TestResources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal TestResources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.ComponentDetection.Detectors.Tests.Mocks.TestResources", typeof(TestResources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to integrationTestCompileClasspath - Compile classpath for source set 'integration test'. - ///+--- commons-io:commons-io:2.5 - ///+--- org.kohsuke:github-api:1.94 - ///| +--- org.apache.commons:commons-lang3:3.7 - ///| +--- commons-codec:commons-codec:1.7 - ///| +--- com.fasterxml.jackson.core:jackson-databind:2.9.2 - ///| | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0 - ///| | \--- com.fasterxml.jackson.core:jackson-core:2.9.2 - ///| \--- commons-io:commons-io:1.4 -> 2.5 - ///+--- org.zeroturnaround:zt-zip: [rest of string was truncated]";. - /// - internal static string GradlewDependencyOutput { - get { - return ResourceManager.GetString("GradlewDependencyOutput", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to org.apache.maven:maven-compat:jar:3.6.1-SNAPSHOT - ///+- org.apache.maven:maven-model:jar:3.6.1-SNAPSHOT:compile - ///+- org.apache.maven:maven-model-builder:jar:3.6.1-SNAPSHOT:compile - ///| \- org.apache.maven:maven-builder-support:jar:3.6.1-SNAPSHOT:compile - ///+- org.apache.maven:maven-settings:jar:3.6.1-SNAPSHOT:compile - ///+- org.apache.maven:maven-settings-builder:jar:3.6.1-SNAPSHOT:compile - ///| \- org.sonatype.plexus:plexus-sec-dispatcher:jar:1.4:compile - ///| \- org.sonatype.plexus:plexus-cipher:jar:1.7:compile - ///+- [rest of string was truncated]";. - /// - internal static string MvnCliDependencyOutput { - get { - return ResourceManager.GetString("MvnCliDependencyOutput", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "version": 3, - /// "targets": { - /// ".NETCoreApp,Version=v2.2": { - /// "CommandLineParser/2.8.0": { - /// "type": "package", - /// "compile": { - /// "lib/netstandard2.0/_._": {} - /// }, - /// "runtime": { - /// "lib/netstandard2.0/CommandLine.dll": {} - /// } - /// }, - /// "coverlet.msbuild/2.5.1": { - /// "type": "package", - /// "build": { - /// "build/netstandard2.0/coverlet.msbuild.props": {}, - /// "build/netstandard2.0/coverlet.msbuild.targets": {} - /// } - /// }, - /// "DotNet.Glob/2.1.1": { - /// "type": "package [rest of string was truncated]";. - /// - internal static string project_assets_2_2 { - get { - return ResourceManager.GetString("project_assets_2_2", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "version": 3, - /// "targets": { - /// ".NETCoreApp,Version=v2.2": { - /// "coverlet.msbuild/2.5.1": { - /// "type": "package", - /// "build": { - /// "build/netstandard2.0/coverlet.msbuild.props": {}, - /// "build/netstandard2.0/coverlet.msbuild.targets": {} - /// } - /// }, - /// "DotNet.Glob/2.1.1": { - /// "type": "package", - /// "dependencies": { - /// "NETStandard.Library": "1.6.1" - /// }, - /// "compile": { - /// "lib/netstandard1.1/DotNet.Glob.dll": {} - /// }, - /// "runtime": { - /// "lib/netstandard1.1/DotNet.Glob.dll": {} - /// [rest of string was truncated]";. - /// - internal static string project_assets_2_2_additional { - get { - return ResourceManager.GetString("project_assets_2_2_additional", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to { - /// "version": 3, - /// "targets": { - /// ".NETCoreApp,Version=v3.1": { - /// "Microsoft.Extensions.DependencyModel/3.0.0": { - /// "type": "package", - /// "dependencies": { - /// "System.Text.Json": "4.6.0" - /// }, - /// "compile": { - /// "lib/netstandard2.0/Microsoft.Extensions.DependencyModel.dll": {} - /// }, - /// "runtime": { - /// "lib/netstandard2.0/Microsoft.Extensions.DependencyModel.dll": {} - /// } - /// }, - /// "Microsoft. [rest of string was truncated]";. - /// - internal static string project_assets_3_1 { - get { - return ResourceManager.GetString("project_assets_3_1", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.ComponentDetection.Detectors.Tests.Mocks { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class TestResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal TestResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.ComponentDetection.Detectors.Tests.Mocks.TestResources", typeof(TestResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to integrationTestCompileClasspath - Compile classpath for source set 'integration test'. + ///+--- commons-io:commons-io:2.5 + ///+--- org.kohsuke:github-api:1.94 + ///| +--- org.apache.commons:commons-lang3:3.7 + ///| +--- commons-codec:commons-codec:1.7 + ///| +--- com.fasterxml.jackson.core:jackson-databind:2.9.2 + ///| | +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0 + ///| | \--- com.fasterxml.jackson.core:jackson-core:2.9.2 + ///| \--- commons-io:commons-io:1.4 -> 2.5 + ///+--- org.zeroturnaround:zt-zip: [rest of string was truncated]";. + /// + internal static string GradlewDependencyOutput { + get { + return ResourceManager.GetString("GradlewDependencyOutput", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to org.apache.maven:maven-compat:jar:3.6.1-SNAPSHOT + ///+- org.apache.maven:maven-model:jar:3.6.1-SNAPSHOT:compile + ///+- org.apache.maven:maven-model-builder:jar:3.6.1-SNAPSHOT:compile + ///| \- org.apache.maven:maven-builder-support:jar:3.6.1-SNAPSHOT:compile + ///+- org.apache.maven:maven-settings:jar:3.6.1-SNAPSHOT:compile + ///+- org.apache.maven:maven-settings-builder:jar:3.6.1-SNAPSHOT:compile + ///| \- org.sonatype.plexus:plexus-sec-dispatcher:jar:1.4:compile + ///| \- org.sonatype.plexus:plexus-cipher:jar:1.7:compile + ///+- [rest of string was truncated]";. + /// + internal static string MvnCliDependencyOutput { + get { + return ResourceManager.GetString("MvnCliDependencyOutput", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "version": "1", + /// "pip_version": "24.0", + /// "install": [ + /// { + /// "download_info": { + /// "url": "https://files.pythonhosted.org/packages/72/c3/532326adbb2b76f709e3e582aeefd0a85bd7454599ff450d90dd9540f5ed/jupyterlab-4.2.0-py3-none-any.whl", + /// "archive_info": { + /// "hash": "sha256=0dfe9278e25a145362289c555d9beb505697d269c10e99909766af7c440ad3cc", + /// "hashes": { + /// "sha256": "0dfe9278e25a145362289c555d9beb505697d269c10e99909766af7c440ad3cc" + /// } + /// [rest of string was truncated]";. + /// + internal static string pip_report_jupyterlab { + get { + return ResourceManager.GetString("pip_report_jupyterlab", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "version": "1", + /// "pip_version": "24.0", + /// "install": [ + /// { + /// "download_info": { + /// "url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", + /// "archive_info": { + /// "hash": "sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + /// "hashes": { + /// "sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + /// } + /// } /// [rest of string was truncated]";. + /// + internal static string pip_report_multi_pkg { + get { + return ResourceManager.GetString("pip_report_multi_pkg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "version": "1", + /// "pip_version": "24.0", + /// "install": [ + /// { + /// "download_info": { + /// "url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", + /// "archive_info": { + /// "hash": "sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + /// "hashes": { + /// "sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + /// } + /// } /// [rest of string was truncated]";. + /// + internal static string pip_report_single_pkg { + get { + return ResourceManager.GetString("pip_report_single_pkg", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "version": "2", + /// "pip_version": "24.0", + /// "install": [ + /// { + /// "download_info": { + /// "url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", + /// "archive_info": { + /// "hash": "sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + /// "hashes": { + /// "sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + /// } + /// } /// [rest of string was truncated]";. + /// + internal static string pip_report_single_pkg_bad_version { + get { + return ResourceManager.GetString("pip_report_single_pkg_bad_version", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "version": 3, + /// "targets": { + /// ".NETCoreApp,Version=v2.2": { + /// "CommandLineParser/2.8.0": { + /// "type": "package", + /// "compile": { + /// "lib/netstandard2.0/_._": {} + /// }, + /// "runtime": { + /// "lib/netstandard2.0/CommandLine.dll": {} + /// } + /// }, + /// "coverlet.msbuild/2.5.1": { + /// "type": "package", + /// "build": { + /// "build/netstandard2.0/coverlet.msbuild.props": {}, + /// "build/netstandard2.0/coverlet.msbuild.targets": {} + /// } + /// }, + /// "DotNet.Glob/2.1.1": { + /// "type": "package [rest of string was truncated]";. + /// + internal static string project_assets_2_2 { + get { + return ResourceManager.GetString("project_assets_2_2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "version": 3, + /// "targets": { + /// ".NETCoreApp,Version=v2.2": { + /// "coverlet.msbuild/2.5.1": { + /// "type": "package", + /// "build": { + /// "build/netstandard2.0/coverlet.msbuild.props": {}, + /// "build/netstandard2.0/coverlet.msbuild.targets": {} + /// } + /// }, + /// "DotNet.Glob/2.1.1": { + /// "type": "package", + /// "dependencies": { + /// "NETStandard.Library": "1.6.1" + /// }, + /// "compile": { + /// "lib/netstandard1.1/DotNet.Glob.dll": {} + /// }, + /// "runtime": { + /// "lib/netstandard1.1/DotNet.Glob.dll": {} /// [rest of string was truncated]";. + /// + internal static string project_assets_2_2_additional { + get { + return ResourceManager.GetString("project_assets_2_2_additional", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "version": 3, + /// "targets": { + /// ".NETCoreApp,Version=v3.1": { + /// "Microsoft.Extensions.DependencyModel/3.0.0": { + /// "type": "package", + /// "dependencies": { + /// "System.Text.Json": "4.6.0" + /// }, + /// "compile": { + /// "lib/netstandard2.0/Microsoft.Extensions.DependencyModel.dll": {} + /// }, + /// "runtime": { + /// "lib/netstandard2.0/Microsoft.Extensions.DependencyModel.dll": {} + /// } + /// }, + /// "Microsoft. [rest of string was truncated]";. + /// + internal static string project_assets_3_1 { + get { + return ResourceManager.GetString("project_assets_3_1", resourceCulture); + } + } + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/TestResources.resx b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/TestResources.resx index e8eab69ee..41bd0d954 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/TestResources.resx +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/TestResources.resx @@ -124,6 +124,18 @@ MvnCliDependencyOutput.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + pip_report_jupyterlab.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + pip_report_multi_pkg.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + pip_report_single_pkg.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + pip_report_single_pkg_bad_version.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\project_assets_2_2.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_jupyterlab.json b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_jupyterlab.json new file mode 100644 index 000000000..9d46f280b --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_jupyterlab.json @@ -0,0 +1,5382 @@ +{ + "version": "1", + "pip_version": "24.0", + "install": [ + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/72/c3/532326adbb2b76f709e3e582aeefd0a85bd7454599ff450d90dd9540f5ed/jupyterlab-4.2.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=0dfe9278e25a145362289c555d9beb505697d269c10e99909766af7c440ad3cc", + "hashes": { + "sha256": "0dfe9278e25a145362289c555d9beb505697d269c10e99909766af7c440ad3cc" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": true, + "metadata": { + "metadata_version": "2.3", + "name": "jupyterlab", + "version": "4.2.0", + "summary": "JupyterLab computational environment", + "description": "**[Installation](#installation)** |\n**[Documentation](https://jupyterlab.readthedocs.io)** |\n**[Contributing](#contributing)** |\n**[License](#license)** |\n**[Team](#team)** |\n**[Getting help](#getting-help)** |\n\n# [JupyterLab](https://jupyterlab.readthedocs.io)\n\n[![PyPI version](https://badge.fury.io/py/jupyterlab.svg)](https://badge.fury.io/py/jupyterlab)\n[![Downloads](https://static.pepy.tech/badge/jupyterlab/month)](https://pepy.tech/project/jupyterlab)\n[![Build Status](https://github.com/jupyterlab/jupyterlab/workflows/Linux%20Tests/badge.svg)](https://github.com/jupyterlab/jupyterlab/actions?query=branch%3Amain+workflow%3A%22Linux+Tests%22)\n[![Build Status](https://github.com/jupyterlab/jupyterlab/workflows/Windows%20Tests/badge.svg)](https://github.com/jupyterlab/jupyterlab/actions?query=branch%3Amain+workflow%3A%22Windows+Tests%22)\n[![Documentation Status](https://readthedocs.org/projects/jupyterlab/badge/?version=stable)](http://jupyterlab.readthedocs.io/en/stable/)\n[![Crowdin](https://badges.crowdin.net/jupyterlab/localized.svg)](https://crowdin.com/project/jupyterlab)\n[![GitHub](https://img.shields.io/badge/issue_tracking-github-blue.svg)](https://github.com/jupyterlab/jupyterlab/issues)\n[![Discourse](https://img.shields.io/badge/help_forum-discourse-blue.svg)](https://discourse.jupyter.org/c/jupyterlab)\n[![Gitter](https://img.shields.io/badge/social_chat-gitter-blue.svg)](https://gitter.im/jupyterlab/jupyterlab)\n[![Gitpod](https://img.shields.io/badge/gitpod_editor-open-blue.svg)](https://gitpod.io/#https://github.com/jupyterlab/jupyterlab)\n\n[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyterlab/jupyterlab-demo/HEAD?urlpath=lab/tree/demo)\n\nAn extensible environment for interactive and reproducible computing, based on the\nJupyter Notebook and Architecture.\n\n[JupyterLab](http://jupyterlab.readthedocs.io/en/stable/) is the next-generation user interface for [Project Jupyter](https://jupyter.org) offering\nall the familiar building blocks of the classic Jupyter Notebook (notebook,\nterminal, text editor, file browser, rich outputs, etc.) in a flexible and\npowerful user interface.\n\nJupyterLab can be extended using [npm](https://www.npmjs.com/) packages\nthat use our public APIs. The _prebuilt_ extensions can be distributed\nvia [PyPI](https://pypi.org/search/?q=jupyterlab&o=-created&c=Framework+%3A%3A+Jupyter),\nconda, and other package managers. The _source_ extensions can be installed\ndirectly from npm (search for [jupyterlab-extension](https://www.npmjs.com/search?q=keywords:jupyterlab-extension)) but require an additional build step.\nYou can also find JupyterLab extensions exploring GitHub topic [jupyterlab-extension](https://github.com/topics/jupyterlab-extension).\nTo learn more about extensions, see the [user documentation](https://jupyterlab.readthedocs.io/en/latest/user/extensions.html).\n\nRead the current JupyterLab documentation on [ReadTheDocs](http://jupyterlab.readthedocs.io/en/stable/).\n\n> [!IMPORTANT]\n> JupyterLab 3 will reach its end of maintenance date on May 15, 2024, anywhere on Earth. To help us make this transition, fixes for critical issues will still be backported until December 31, 2024. If you are still running JupyterLab 3, we strongly encourage you to **upgrade to JupyterLab 4 as soon as possible.** For more information, see [JupyterLab 3 end of maintenance](https://blog.jupyter.org/jupyterlab-3-end-of-maintenance-879778927db2) on the Jupyter Blog.\n\n---\n\n## Getting started\n\n### Installation\n\nIf you use [conda](https://docs.conda.io/en/latest/), [mamba](https://mamba.readthedocs.io/en/latest/), or [pip](https://docs.python.org/3/installing/index.html), you can install JupyterLab with one of the following commands.\n\n- If you use conda:\n ```shell\n conda install -c conda-forge jupyterlab\n ```\n- If you use mamba:\n ```shell\n mamba install -c conda-forge jupyterlab\n ```\n- If you use pip:\n ```shell\n pip install jupyterlab\n ```\n If installing using `pip install --user`, you must add the user-level `bin` directory to your `PATH` environment variable in order to launch `jupyter lab`. If you are using a Unix derivative (e.g., FreeBSD, GNU/Linux, macOS), you can do this by running `export PATH=\"$HOME/.local/bin:$PATH\"`. If you are using a macOS version that comes with Python 2, run `pip3` instead of `pip`.\n\nFor more detailed instructions, consult the [installation guide](http://jupyterlab.readthedocs.io/en/latest/getting_started/installation.html). Project installation instructions from the git sources are available in the [contributor documentation](CONTRIBUTING.md).\n\n#### Installing with Previous Versions of Jupyter Notebook\n\nWhen using a version of Jupyter Notebook earlier than 5.3, the following command must be run after installing JupyterLab to enable the JupyterLab server extension:\n\n```bash\njupyter serverextension enable --py jupyterlab --sys-prefix\n```\n\n### Running\n\nStart up JupyterLab using:\n\n```bash\njupyter lab\n```\n\nJupyterLab will open automatically in the browser. See the [documentation](http://jupyterlab.readthedocs.io/en/latest/getting_started/starting.html) for additional details.\n\nIf you encounter an error like \"Command 'jupyter' not found\", please make sure `PATH` environment variable is set correctly. Alternatively, you can start up JupyterLab using `~/.local/bin/jupyter lab` without changing the `PATH` environment variable.\n\n### Prerequisites and Supported Browsers\n\nThe latest versions of the following browsers are currently _known to work_:\n\n- Firefox\n- Chrome\n- Safari\n\nSee our [documentation](http://jupyterlab.readthedocs.io/en/latest/getting_started/installation.html) for additional details.\n\n---\n\n## Getting help\n\nWe encourage you to ask questions on the [Discourse forum](https://discourse.jupyter.org/c/jupyterlab). A question answered there can become a useful resource for others.\n\n### Bug report\n\nTo report a bug please read the [guidelines](https://jupyterlab.readthedocs.io/en/latest/getting_started/issue.html) and then open a [Github issue](https://github.com/jupyterlab/jupyterlab/issues/new?labels=bug%2C+status%3ANeeds+Triage&template=bug_report.md). To keep resolved issues self-contained, the [lock bot](https://github.com/apps/lock) will lock closed issues as resolved after a period of inactivity. If a related discussion is still needed after an issue is locked, please open a new issue and reference the old issue.\n\n### Feature request\n\nWe also welcome suggestions for new features as they help make the project more useful for everyone. To request a feature please use the [feature request template](https://github.com/jupyterlab/jupyterlab/issues/new?labels=enhancement%2C+status%3ANeeds+Triage&template=feature_request.md).\n\n---\n\n## Development\n\n### Extending JupyterLab\n\nTo start developing an extension for JupyterLab, see the [developer documentation](https://jupyterlab.readthedocs.io/en/latest/extension/extension_dev.html) and the [API docs](https://jupyterlab.readthedocs.io/en/latest/api/).\n\n### Contributing\n\nTo contribute code or documentation to JupyterLab itself, please read the [contributor documentation](https://jupyterlab.readthedocs.io/en/latest/developer/contributing.html).\n\nJupyterLab follows the Jupyter [Community Guides](https://jupyter.readthedocs.io/en/latest/community/content-community.html).\n\n### License\n\nJupyterLab uses a shared copyright model that enables all contributors to maintain the\ncopyright on their contributions. All code is licensed under the terms of the revised [BSD license](https://github.com/jupyterlab/jupyterlab/blob/main/LICENSE).\n\n### Team\n\nJupyterLab is part of [Project Jupyter](https://jupyter.org/) and is developed by an open community. The maintenance team is assisted by a much larger group of contributors to JupyterLab and Project Jupyter as a whole.\n\nJupyterLab's current maintainers are listed in alphabetical order, with affiliation, and main areas of contribution:\n\n- Mehmet Bektas, Netflix (general development, extensions).\n- Alex Bozarth, IBM (general development, extensions).\n- Eric Charles, Datalayer, (general development, extensions).\n- Frédéric Collonval, WebScIT (general development, extensions).\n- Martha Cryan, Mito (general development, extensions).\n- Afshin Darian, QuantStack (co-creator, application/high-level architecture,\n prolific contributions throughout the code base).\n- Vidar T. Fauske, JPMorgan Chase (general development, extensions).\n- Brian Granger, AWS (co-creator, strategy, vision, management, UI/UX design,\n architecture).\n- Jason Grout, Databricks (co-creator, vision, general development).\n- Michał Krassowski, Quansight (general development, extensions).\n- Max Klein, JPMorgan Chase (UI Package, build system, general development, extensions).\n- Gonzalo Peña-Castellanos, QuanSight (general development, i18n, extensions).\n- Fernando Perez, UC Berkeley (co-creator, vision).\n- Isabela Presedo-Floyd, QuanSight Labs (design/UX).\n- Steven Silvester, MongoDB (co-creator, release management, packaging,\n prolific contributions throughout the code base).\n- Jeremy Tuloup, QuantStack (general development, extensions).\n\nMaintainer emeritus:\n\n- Chris Colbert, Project Jupyter (co-creator, application/low-level architecture,\n technical leadership, vision, PhosphorJS)\n- Jessica Forde, Project Jupyter (demo, documentation)\n- Tim George, Cal Poly (UI/UX design, strategy, management, user needs analysis).\n- Cameron Oelsen, Cal Poly (UI/UX design).\n- Ian Rose, Quansight/City of LA (general core development, extensions).\n- Andrew Schlaepfer, Bloomberg (general development, extensions).\n- Saul Shanabrook, Quansight (general development, extensions)\n\nThis list is provided to give the reader context on who we are and how our team functions.\nTo be listed, please submit a pull request with your information.\n\n---\n\n### Weekly Dev Meeting\n\nWe have videoconference meetings every week where we discuss what we have been working on and get feedback from one another.\n\nAnyone is welcome to attend, if they would like to discuss a topic or just listen in.\n\n- When: Wednesdays [9:00 AM Pacific Time (USA)](https://www.thetimezoneconverter.com/?t=9%3A00%20am&tz=San%20Francisco&)\n- Where: [`jovyan` Zoom](https://zoom.us/my/jovyan?pwd=c0JZTHlNdS9Sek9vdzR3aTJ4SzFTQT09)\n- What: [Meeting notes](https://hackmd.io/Y7fBMQPSQ1C08SDGI-fwtg?both)\n\n> Notes are archived on [GitHub Jupyter Frontends team compass](https://github.com/jupyterlab/frontends-team-compass/issues).\n", + "description_content_type": "text/markdown", + "keywords": [ + "ipython", + "jupyter" + ], + "author_email": "Jupyter Development Team ", + "license": "Copyright (c) 2015-2022 Project Jupyter Contributors\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nSemver File License\n===================\n\nThe semver.py file is from https://github.com/podhmo/python-semver\nwhich is licensed under the \"MIT\" license. See the semver.py file for details.", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Framework :: Jupyter", + "Framework :: Jupyter :: JupyterLab", + "Framework :: Jupyter :: JupyterLab :: 4", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" + ], + "requires_dist": [ + "async-lru>=1.0.0", + "httpx>=0.25.0", + "importlib-metadata>=4.8.3; python_version < '3.10'", + "importlib-resources>=1.4; python_version < '3.9'", + "ipykernel>=6.5.0", + "jinja2>=3.0.3", + "jupyter-core", + "jupyter-lsp>=2.0.0", + "jupyter-server<3,>=2.4.0", + "jupyterlab-server<3,>=2.27.1", + "notebook-shim>=0.2", + "packaging", + "tomli>=1.2.2; python_version < '3.11'", + "tornado>=6.2.0", + "traitlets", + "build; extra == 'dev'", + "bump2version; extra == 'dev'", + "coverage; extra == 'dev'", + "hatch; extra == 'dev'", + "pre-commit; extra == 'dev'", + "pytest-cov; extra == 'dev'", + "ruff==0.3.5; extra == 'dev'", + "jsx-lexer; extra == 'docs'", + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme>=0.13.0; extra == 'docs'", + "pytest; extra == 'docs'", + "pytest-check-links; extra == 'docs'", + "pytest-jupyter; extra == 'docs'", + "sphinx-copybutton; extra == 'docs'", + "sphinx<7.3.0,>=1.8; extra == 'docs'", + "altair==5.3.0; extra == 'docs-screenshots'", + "ipython==8.16.1; extra == 'docs-screenshots'", + "ipywidgets==8.1.2; extra == 'docs-screenshots'", + "jupyterlab-geojson==3.4.0; extra == 'docs-screenshots'", + "jupyterlab-language-pack-zh-cn==4.1.post2; extra == 'docs-screenshots'", + "matplotlib==3.8.3; extra == 'docs-screenshots'", + "nbconvert>=7.0.0; extra == 'docs-screenshots'", + "pandas==2.2.1; extra == 'docs-screenshots'", + "scipy==1.12.0; extra == 'docs-screenshots'", + "vega-datasets==0.9.0; extra == 'docs-screenshots'", + "coverage; extra == 'test'", + "pytest-check-links>=0.7; extra == 'test'", + "pytest-console-scripts; extra == 'test'", + "pytest-cov; extra == 'test'", + "pytest-jupyter>=0.5.3; extra == 'test'", + "pytest-timeout; extra == 'test'", + "pytest-tornasync; extra == 'test'", + "pytest>=7.0; extra == 'test'", + "requests; extra == 'test'", + "requests-cache; extra == 'test'", + "virtualenv; extra == 'test'", + "copier<10,>=8; extra == 'upgrade-extension'", + "jinja2-time<0.3; extra == 'upgrade-extension'", + "pydantic<2.0; extra == 'upgrade-extension'", + "pyyaml-include<2.0; extra == 'upgrade-extension'", + "tomli-w<2.0; extra == 'upgrade-extension'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://jupyter.org", + "Changelog, https://jupyterlab.readthedocs.io/en/stable/getting_started/changelog.html", + "Documentation, https://jupyterlab.readthedocs.io", + "Source, https://github.com/jupyterlab/jupyterlab", + "Issues, https://github.com/jupyterlab/jupyterlab/issues/new/choose", + "Gitter, https://gitter.im/jupyterlab/jupyterlab", + "Pypi, https://pypi.org/project/jupyterlab" + ], + "provides_extra": [ + "dev", + "docs", + "docs-screenshots", + "test", + "upgrade-extension" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/fa/9f/3c3503693386c4b0f245eaf5ca6198e3b28879ca0a40bde6b0e319793453/async_lru-2.0.4-py3-none-any.whl", + "archive_info": { + "hash": "sha256=ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224", + "hashes": { + "sha256": "ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "async-lru", + "version": "2.0.4", + "summary": "Simple LRU cache for asyncio", + "description": "async-lru\n=========\n\n:info: Simple lru cache for asyncio\n\n.. image:: https://github.com/aio-libs/async-lru/actions/workflows/ci-cd.yml/badge.svg?event=push\n :target: https://github.com/aio-libs/async-lru/actions/workflows/ci-cd.yml?query=event:push\n :alt: GitHub Actions CI/CD workflows status\n\n.. image:: https://img.shields.io/pypi/v/async-lru.svg?logo=Python&logoColor=white\n :target: https://pypi.org/project/async-lru\n :alt: async-lru @ PyPI\n\n.. image:: https://codecov.io/gh/aio-libs/async-lru/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/aio-libs/async-lru\n\n.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat\n :target: https://matrix.to/#/%23aio-libs:matrix.org\n :alt: Matrix Room — #aio-libs:matrix.org\n\n.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat\n :target: https://matrix.to/#/%23aio-libs-space:matrix.org\n :alt: Matrix Space — #aio-libs-space:matrix.org\n\nInstallation\n------------\n\n.. code-block:: shell\n\n pip install async-lru\n\nUsage\n-----\n\nThis package is a port of Python's built-in `functools.lru_cache `_ function for `asyncio `_. To better handle async behaviour, it also ensures multiple concurrent calls will only result in 1 call to the wrapped function, with all ``await``\\s receiving the result of that call when it completes.\n\n.. code-block:: python\n\n import asyncio\n\n import aiohttp\n from async_lru import alru_cache\n\n\n @alru_cache(maxsize=32)\n async def get_pep(num):\n resource = 'http://www.python.org/dev/peps/pep-%04d/' % num\n async with aiohttp.ClientSession() as session:\n try:\n async with session.get(resource) as s:\n return await s.read()\n except aiohttp.ClientError:\n return 'Not Found'\n\n\n async def main():\n for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:\n pep = await get_pep(n)\n print(n, len(pep))\n\n print(get_pep.cache_info())\n # CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)\n\n # closing is optional, but highly recommended\n await get_pep.cache_close()\n\n\n asyncio.run(main())\n\n\nTTL (time-to-live, expiration on timeout) is supported by accepting `ttl` configuration\nparameter (off by default):\n\n.. code-block:: python\n\n @alru_cache(ttl=5)\n async def func(arg):\n return arg * 2\n\n\nThe library supports explicit invalidation for specific function call by\n`cache_invalidate()`:\n\n.. code-block:: python\n\n @alru_cache(ttl=5)\n async def func(arg1, arg2):\n return arg1 + arg2\n\n func.cache_invalidate(1, arg2=2)\n\nThe method returns `True` if corresponding arguments set was cached already, `False`\notherwise.\n\n\nPython 3.8+ is required\n\nThanks\n------\n\nThe library was donated by `Ocean S.A. `_\n\nThanks to the company for contribution.\n", + "description_content_type": "text/x-rst", + "keywords": [ + "asyncio", + "lru", + "lru_cache" + ], + "home_page": "https://github.com/aio-libs/async-lru", + "maintainer": "aiohttp team ", + "maintainer_email": "team@aiohttp.org", + "license": "MIT License", + "classifier": [ + "License :: OSI Approved :: MIT License", + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Development Status :: 5 - Production/Stable", + "Framework :: AsyncIO" + ], + "requires_dist": [ + "typing-extensions (>=4.0.0) ; python_version < \"3.11\"" + ], + "requires_python": ">=3.8", + "project_url": [ + "Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org", + "Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org", + "CI: GitHub Actions, https://github.com/aio-libs/async-lru/actions", + "GitHub: repo, https://github.com/aio-libs/async-lru" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/41/7b/ddacf6dcebb42466abd03f368782142baa82e08fc0c1f8eaa05b4bae87d5/httpx-0.27.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5", + "hashes": { + "sha256": "71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "httpx", + "version": "0.27.0", + "summary": "The next generation HTTP client.", + "description": "

\n HTTPX\n

\n\n

HTTPX - A next-generation HTTP client for Python.

\n\n

\n\n \"Test\n\n\n \"Package\n\n

\n\nHTTPX is a fully featured HTTP client library for Python 3. It includes **an integrated\ncommand line client**, has support for both **HTTP/1.1 and HTTP/2**, and provides both **sync\nand async APIs**.\n\n---\n\nInstall HTTPX using pip:\n\n```shell\n$ pip install httpx\n```\n\nNow, let's get started:\n\n```pycon\n>>> import httpx\n>>> r = httpx.get('https://www.example.org/')\n>>> r\n\n>>> r.status_code\n200\n>>> r.headers['content-type']\n'text/html; charset=UTF-8'\n>>> r.text\n'\\n\\n\\nExample Domain...'\n```\n\nOr, using the command-line client.\n\n```shell\n$ pip install 'httpx[cli]' # The command line client is an optional dependency.\n```\n\nWhich now allows us to use HTTPX directly from the command-line...\n\n

\n httpx --help\n

\n\nSending a request...\n\n

\n httpx http://httpbin.org/json\n

\n\n## Features\n\nHTTPX builds on the well-established usability of `requests`, and gives you:\n\n* A broadly [requests-compatible API](https://www.python-httpx.org/compatibility/).\n* An integrated command-line client.\n* HTTP/1.1 [and HTTP/2 support](https://www.python-httpx.org/http2/).\n* Standard synchronous interface, but with [async support if you need it](https://www.python-httpx.org/async/).\n* Ability to make requests directly to [WSGI applications](https://www.python-httpx.org/advanced/#calling-into-python-web-apps) or [ASGI applications](https://www.python-httpx.org/async/#calling-into-python-web-apps).\n* Strict timeouts everywhere.\n* Fully type annotated.\n* 100% test coverage.\n\nPlus all the standard features of `requests`...\n\n* International Domains and URLs\n* Keep-Alive & Connection Pooling\n* Sessions with Cookie Persistence\n* Browser-style SSL Verification\n* Basic/Digest Authentication\n* Elegant Key/Value Cookies\n* Automatic Decompression\n* Automatic Content Decoding\n* Unicode Response Bodies\n* Multipart File Uploads\n* HTTP(S) Proxy Support\n* Connection Timeouts\n* Streaming Downloads\n* .netrc Support\n* Chunked Requests\n\n## Installation\n\nInstall with pip:\n\n```shell\n$ pip install httpx\n```\n\nOr, to include the optional HTTP/2 support, use:\n\n```shell\n$ pip install httpx[http2]\n```\n\nHTTPX requires Python 3.8+.\n\n## Documentation\n\nProject documentation is available at [https://www.python-httpx.org/](https://www.python-httpx.org/).\n\nFor a run-through of all the basics, head over to the [QuickStart](https://www.python-httpx.org/quickstart/).\n\nFor more advanced topics, see the [Advanced Usage](https://www.python-httpx.org/advanced/) section, the [async support](https://www.python-httpx.org/async/) section, or the [HTTP/2](https://www.python-httpx.org/http2/) section.\n\nThe [Developer Interface](https://www.python-httpx.org/api/) provides a comprehensive API reference.\n\nTo find out about tools that integrate with HTTPX, see [Third Party Packages](https://www.python-httpx.org/third_party_packages/).\n\n## Contribute\n\nIf you want to contribute with HTTPX check out the [Contributing Guide](https://www.python-httpx.org/contributing/) to learn how to start.\n\n## Dependencies\n\nThe HTTPX project relies on these excellent libraries:\n\n* `httpcore` - The underlying transport implementation for `httpx`.\n * `h11` - HTTP/1.1 support.\n* `certifi` - SSL certificates.\n* `idna` - Internationalized domain name support.\n* `sniffio` - Async library autodetection.\n\nAs well as these optional installs:\n\n* `h2` - HTTP/2 support. *(Optional, with `httpx[http2]`)*\n* `socksio` - SOCKS proxy support. *(Optional, with `httpx[socks]`)*\n* `rich` - Rich terminal support. *(Optional, with `httpx[cli]`)*\n* `click` - Command line client support. *(Optional, with `httpx[cli]`)*\n* `brotli` or `brotlicffi` - Decoding for \"brotli\" compressed responses. *(Optional, with `httpx[brotli]`)*\n\nA huge amount of credit is due to `requests` for the API layout that\nmuch of this work follows, as well as to `urllib3` for plenty of design\ninspiration around the lower-level networking details.\n\n---\n\n

HTTPX is BSD licensed code.
Designed & crafted with care.

— 🦋 —

\n\n## Release Information\n\n### Deprecated\n\n* The `app=...` shortcut has been deprecated. Use the explicit style of `transport=httpx.WSGITransport()` or `transport=httpx.ASGITransport()` instead.\n\n### Fixed\n\n* Respect the `http1` argument while configuring proxy transports. (#3023)\n* Fix RFC 2069 mode digest authentication. (#3045)\n\n\n---\n\n[Full changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)\n", + "description_content_type": "text/markdown", + "author_email": "Tom Christie ", + "classifier": [ + "Development Status :: 4 - Beta", + "Environment :: Web Environment", + "Framework :: AsyncIO", + "Framework :: Trio", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Internet :: WWW/HTTP" + ], + "requires_dist": [ + "anyio", + "certifi", + "httpcore==1.*", + "idna", + "sniffio", + "brotli; (platform_python_implementation == 'CPython') and extra == 'brotli'", + "brotlicffi; (platform_python_implementation != 'CPython') and extra == 'brotli'", + "click==8.*; extra == 'cli'", + "pygments==2.*; extra == 'cli'", + "rich<14,>=10; extra == 'cli'", + "h2<5,>=3; extra == 'http2'", + "socksio==1.*; extra == 'socks'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Changelog, https://github.com/encode/httpx/blob/master/CHANGELOG.md", + "Documentation, https://www.python-httpx.org", + "Homepage, https://github.com/encode/httpx", + "Source, https://github.com/encode/httpx" + ], + "provides_extra": [ + "brotli", + "cli", + "http2", + "socks" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/78/d4/e5d7e4f2174f8a4d63c8897d79eb8fe2503f7ecc03282fee1fa2719c2704/httpcore-1.0.5-py3-none-any.whl", + "archive_info": { + "hash": "sha256=421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5", + "hashes": { + "sha256": "421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "httpcore", + "version": "1.0.5", + "summary": "A minimal low-level HTTP client.", + "description": "# HTTP Core\n\n[![Test Suite](https://github.com/encode/httpcore/workflows/Test%20Suite/badge.svg)](https://github.com/encode/httpcore/actions)\n[![Package version](https://badge.fury.io/py/httpcore.svg)](https://pypi.org/project/httpcore/)\n\n> *Do one thing, and do it well.*\n\nThe HTTP Core package provides a minimal low-level HTTP client, which does\none thing only. Sending HTTP requests.\n\nIt does not provide any high level model abstractions over the API,\ndoes not handle redirects, multipart uploads, building authentication headers,\ntransparent HTTP caching, URL parsing, session cookie handling,\ncontent or charset decoding, handling JSON, environment based configuration\ndefaults, or any of that Jazz.\n\nSome things HTTP Core does do:\n\n* Sending HTTP requests.\n* Thread-safe / task-safe connection pooling.\n* HTTP(S) proxy & SOCKS proxy support.\n* Supports HTTP/1.1 and HTTP/2.\n* Provides both sync and async interfaces.\n* Async backend support for `asyncio` and `trio`.\n\n## Requirements\n\nPython 3.8+\n\n## Installation\n\nFor HTTP/1.1 only support, install with:\n\n```shell\n$ pip install httpcore\n```\n\nThere are also a number of optional extras available...\n\n```shell\n$ pip install httpcore['asyncio,trio,http2,socks']\n```\n\n# Sending requests\n\nSend an HTTP request:\n\n```python\nimport httpcore\n\nresponse = httpcore.request(\"GET\", \"https://www.example.com/\")\n\nprint(response)\n# \nprint(response.status)\n# 200\nprint(response.headers)\n# [(b'Accept-Ranges', b'bytes'), (b'Age', b'557328'), (b'Cache-Control', b'max-age=604800'), ...]\nprint(response.content)\n# b'\\n\\n\\nExample Domain\\n\\n\\n ...'\n```\n\nThe top-level `httpcore.request()` function is provided for convenience. In practice whenever you're working with `httpcore` you'll want to use the connection pooling functionality that it provides.\n\n```python\nimport httpcore\n\nhttp = httpcore.ConnectionPool()\nresponse = http.request(\"GET\", \"https://www.example.com/\")\n```\n\nOnce you're ready to get going, [head over to the documentation](https://www.encode.io/httpcore/).\n\n## Motivation\n\nYou *probably* don't want to be using HTTP Core directly. It might make sense if\nyou're writing something like a proxy service in Python, and you just want\nsomething at the lowest possible level, but more typically you'll want to use\na higher level client library, such as `httpx`.\n\nThe motivation for `httpcore` is:\n\n* To provide a reusable low-level client library, that other packages can then build on top of.\n* To provide a *really clear interface split* between the networking code and client logic,\n so that each is easier to understand and reason about in isolation.\n\n## Dependencies\n\nThe `httpcore` package has the following dependencies...\n\n* `h11`\n* `certifi`\n\nAnd the following optional extras...\n\n* `anyio` - Required by `pip install httpcore['asyncio']`.\n* `trio` - Required by `pip install httpcore['trio']`.\n* `h2` - Required by `pip install httpcore['http2']`.\n* `socksio` - Required by `pip install httpcore['socks']`.\n\n## Versioning\n\nWe use [SEMVER for our versioning policy](https://semver.org/).\n\nFor changes between package versions please see our [project changelog](CHANGELOG.md).\n\nWe recommend pinning your requirements either the most current major version, or a more specific version range:\n\n```python\npip install 'httpcore==1.*'\n```\n# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).\n\n## 1.0.5 (March 27th, 2024)\n\n- Handle `EndOfStream` exception for anyio backend. (#899)\n- Allow trio `0.25.*` series in package dependancies. (#903)\n\n## 1.0.4 (February 21st, 2024)\n\n- Add `target` request extension. (#888)\n- Fix support for connection `Upgrade` and `CONNECT` when some data in the stream has been read. (#882)\n\n## 1.0.3 (February 13th, 2024)\n\n- Fix support for async cancellations. (#880)\n- Fix trace extension when used with socks proxy. (#849)\n- Fix SSL context for connections using the \"wss\" scheme (#869)\n\n## 1.0.2 (November 10th, 2023)\n\n- Fix `float(\"inf\")` timeouts in `Event.wait` function. (#846)\n\n## 1.0.1 (November 3rd, 2023)\n\n- Fix pool timeout to account for the total time spent retrying. (#823)\n- Raise a neater RuntimeError when the correct async deps are not installed. (#826)\n- Add support for synchronous TLS-in-TLS streams. (#840)\n\n## 1.0.0 (October 6th, 2023)\n\nFrom version 1.0 our async support is now optional, as the package has minimal dependencies by default.\n\nFor async support use either `pip install 'httpcore[asyncio]'` or `pip install 'httpcore[trio]'`.\n\nThe project versioning policy is now explicitly governed by SEMVER. See https://semver.org/.\n\n- Async support becomes fully optional. (#809)\n- Add support for Python 3.12. (#807)\n\n## 0.18.0 (September 8th, 2023)\n\n- Add support for HTTPS proxies. (#745, #786)\n- Drop Python 3.7 support. (#727)\n- Handle `sni_hostname` extension with SOCKS proxy. (#774)\n- Handle HTTP/1.1 half-closed connections gracefully. (#641)\n- Change the type of `Extensions` from `Mapping[Str, Any]` to `MutableMapping[Str, Any]`. (#762)\n\n## 0.17.3 (July 5th, 2023)\n\n- Support async cancellations, ensuring that the connection pool is left in a clean state when cancellations occur. (#726)\n- The networking backend interface has [been added to the public API](https://www.encode.io/httpcore/network-backends). Some classes which were previously private implementation detail are now part of the top-level public API. (#699)\n- Graceful handling of HTTP/2 GoAway frames, with requests being transparently retried on a new connection. (#730)\n- Add exceptions when a synchronous `trace callback` is passed to an asynchronous request or an asynchronous `trace callback` is passed to a synchronous request. (#717)\n- Drop Python 3.7 support. (#727)\n\n## 0.17.2 (May 23th, 2023)\n\n- Add `socket_options` argument to `ConnectionPool` and `HTTProxy` classes. (#668)\n- Improve logging with per-module logger names. (#690)\n- Add `sni_hostname` request extension. (#696)\n- Resolve race condition during import of `anyio` package. (#692)\n- Enable TCP_NODELAY for all synchronous sockets. (#651)\n\n## 0.17.1 (May 17th, 2023)\n\n- If 'retries' is set, then allow retries if an SSL handshake error occurs. (#669)\n- Improve correctness of tracebacks on network exceptions, by raising properly chained exceptions. (#678)\n- Prevent connection-hanging behaviour when HTTP/2 connections are closed by a server-sent 'GoAway' frame. (#679)\n- Fix edge-case exception when removing requests from the connection pool. (#680)\n- Fix pool timeout edge-case. (#688)\n\n## 0.17.0 (March 16th, 2023)\n\n- Add DEBUG level logging. (#648)\n- Respect HTTP/2 max concurrent streams when settings updates are sent by server. (#652)\n- Increase the allowable HTTP header size to 100kB. (#647)\n- Add `retries` option to SOCKS proxy classes. (#643)\n\n## 0.16.3 (December 20th, 2022)\n\n- Allow `ws` and `wss` schemes. Allows us to properly support websocket upgrade connections. (#625)\n- Forwarding HTTP proxies use a connection-per-remote-host. Required by some proxy implementations. (#637)\n- Don't raise `RuntimeError` when closing a connection pool with active connections. Removes some error cases when cancellations are used. (#631)\n- Lazy import `anyio`, so that it's no longer a hard dependancy, and isn't imported if unused. (#639)\n\n## 0.16.2 (November 25th, 2022)\n\n- Revert 'Fix async cancellation behaviour', which introduced race conditions. (#627)\n- Raise `RuntimeError` if attempting to us UNIX domain sockets on Windows. (#619)\n\n## 0.16.1 (November 17th, 2022)\n\n- Fix HTTP/1.1 interim informational responses, such as \"100 Continue\". (#605)\n\n## 0.16.0 (October 11th, 2022)\n\n- Support HTTP/1.1 informational responses. (#581)\n- Fix async cancellation behaviour. (#580)\n- Support `h11` 0.14. (#579)\n\n## 0.15.0 (May 17th, 2022)\n\n- Drop Python 3.6 support (#535)\n- Ensure HTTP proxy CONNECT requests include `timeout` configuration. (#506)\n- Switch to explicit `typing.Optional` for type hints. (#513)\n- For `trio` map OSError exceptions to `ConnectError`. (#543)\n\n## 0.14.7 (February 4th, 2022)\n\n- Requests which raise a PoolTimeout need to be removed from the pool queue. (#502)\n- Fix AttributeError that happened when Socks5Connection were terminated. (#501)\n\n## 0.14.6 (February 1st, 2022)\n\n- Fix SOCKS support for `http://` URLs. (#492)\n- Resolve race condition around exceptions during streaming a response. (#491)\n\n## 0.14.5 (January 18th, 2022)\n\n- SOCKS proxy support. (#478)\n- Add proxy_auth argument to HTTPProxy. (#481)\n- Improve error message on 'RemoteProtocolError' exception when server disconnects without sending a response. (#479)\n\n## 0.14.4 (January 5th, 2022)\n\n- Support HTTP/2 on HTTPS tunnelling proxies. (#468)\n- Fix proxy headers missing on HTTP forwarding. (#456)\n- Only instantiate SSL context if required. (#457)\n- More robust HTTP/2 handling. (#253, #439, #440, #441)\n\n## 0.14.3 (November 17th, 2021)\n\n- Fix race condition when removing closed connections from the pool. (#437)\n\n## 0.14.2 (November 16th, 2021)\n\n- Failed connections no longer remain in the pool. (Pull #433)\n\n## 0.14.1 (November 12th, 2021)\n\n- `max_connections` becomes optional. (Pull #429)\n- `certifi` is now included in the install dependancies. (Pull #428)\n- `h2` is now strictly optional. (Pull #428)\n\n## 0.14.0 (November 11th, 2021)\n\nThe 0.14 release is a complete reworking of `httpcore`, comprehensively addressing some underlying issues in the connection pooling, as well as substantially redesigning the API to be more user friendly.\n\nSome of the lower-level API design also makes the components more easily testable in isolation, and the package now has 100% test coverage.\n\nSee [discussion #419](https://github.com/encode/httpcore/discussions/419) for a little more background.\n\nThere's some other neat bits in there too, such as the \"trace\" extension, which gives a hook into inspecting the internal events that occur during the request/response cycle. This extension is needed for the HTTPX cli, in order to...\n\n* Log the point at which the connection is established, and the IP/port on which it is made.\n* Determine if the outgoing request should log as HTTP/1.1 or HTTP/2, rather than having to assume it's HTTP/2 if the --http2 flag was passed. (Which may not actually be true.)\n* Log SSL version info / certificate info.\n\nNote that `curio` support is not currently available in 0.14.0. If you're using `httpcore` with `curio` please get in touch, so we can assess if we ought to prioritize it as a feature or not.\n\n## 0.13.7 (September 13th, 2021)\n\n- Fix broken error messaging when URL scheme is missing, or a non HTTP(S) scheme is used. (Pull #403)\n\n## 0.13.6 (June 15th, 2021)\n\n### Fixed\n\n- Close sockets when read or write timeouts occur. (Pull #365)\n\n## 0.13.5 (June 14th, 2021)\n\n### Fixed\n\n- Resolved niggles with AnyIO EOF behaviours. (Pull #358, #362)\n\n## 0.13.4 (June 9th, 2021)\n\n### Added\n\n- Improved error messaging when URL scheme is missing, or a non HTTP(S) scheme is used. (Pull #354)\n\n### Fixed\n\n- Switched to `anyio` as the default backend implementation when running with `asyncio`. Resolves some awkward [TLS timeout issues](https://github.com/encode/httpx/discussions/1511).\n\n## 0.13.3 (May 6th, 2021)\n\n### Added\n\n- Support HTTP/2 prior knowledge, using `httpcore.SyncConnectionPool(http1=False)`. (Pull #333)\n\n### Fixed\n\n- Handle cases where environment does not provide `select.poll` support. (Pull #331)\n\n## 0.13.2 (April 29th, 2021)\n\n### Added\n\n- Improve error message for specific case of `RemoteProtocolError` where server disconnects without sending a response. (Pull #313)\n\n## 0.13.1 (April 28th, 2021)\n\n### Fixed\n\n- More resiliant testing for closed connections. (Pull #311)\n- Don't raise exceptions on ungraceful connection closes. (Pull #310)\n\n## 0.13.0 (April 21st, 2021)\n\nThe 0.13 release updates the core API in order to match the HTTPX Transport API,\nintroduced in HTTPX 0.18 onwards.\n\nAn example of making requests with the new interface is:\n\n```python\nwith httpcore.SyncConnectionPool() as http:\n status_code, headers, stream, extensions = http.handle_request(\n method=b'GET',\n url=(b'https', b'example.org', 443, b'/'),\n headers=[(b'host', b'example.org'), (b'user-agent', b'httpcore')]\n stream=httpcore.ByteStream(b''),\n extensions={}\n )\n body = stream.read()\n print(status_code, body)\n```\n\n### Changed\n\n- The `.request()` method is now `handle_request()`. (Pull #296)\n- The `.arequest()` method is now `.handle_async_request()`. (Pull #296)\n- The `headers` argument is no longer optional. (Pull #296)\n- The `stream` argument is no longer optional. (Pull #296)\n- The `ext` argument is now named `extensions`, and is no longer optional. (Pull #296)\n- The `\"reason\"` extension keyword is now named `\"reason_phrase\"`. (Pull #296)\n- The `\"reason_phrase\"` and `\"http_version\"` extensions now use byte strings for their values. (Pull #296)\n- The `httpcore.PlainByteStream()` class becomes `httpcore.ByteStream()`. (Pull #296)\n\n### Added\n\n- Streams now support a `.read()` interface. (Pull #296)\n\n### Fixed\n\n- Task cancellation no longer leaks connections from the connection pool. (Pull #305)\n\n## 0.12.3 (December 7th, 2020)\n\n### Fixed\n\n- Abort SSL connections on close rather than waiting for remote EOF when using `asyncio`. (Pull #167)\n- Fix exception raised in case of connect timeouts when using the `anyio` backend. (Pull #236)\n- Fix `Host` header precedence for `:authority` in HTTP/2. (Pull #241, #243)\n- Handle extra edge case when detecting for socket readability when using `asyncio`. (Pull #242, #244)\n- Fix `asyncio` SSL warning when using proxy tunneling. (Pull #249)\n\n## 0.12.2 (November 20th, 2020)\n\n### Fixed\n\n- Properly wrap connect errors on the asyncio backend. (Pull #235)\n- Fix `ImportError` occurring on Python 3.9 when using the HTTP/1.1 sync client in a multithreaded context. (Pull #237)\n\n## 0.12.1 (November 7th, 2020)\n\n### Added\n\n- Add connect retries. (Pull #221)\n\n### Fixed\n\n- Tweak detection of dropped connections, resolving an issue with open files limits on Linux. (Pull #185)\n- Avoid leaking connections when establishing an HTTP tunnel to a proxy has failed. (Pull #223)\n- Properly wrap OS errors when using `trio`. (Pull #225)\n\n## 0.12.0 (October 6th, 2020)\n\n### Changed\n\n- HTTP header casing is now preserved, rather than always sent in lowercase. (#216 and python-hyper/h11#104)\n\n### Added\n\n- Add Python 3.9 to officially supported versions.\n\n### Fixed\n\n- Gracefully handle a stdlib asyncio bug when a connection is closed while it is in a paused-for-reading state. (#201)\n\n## 0.11.1 (September 28nd, 2020)\n\n### Fixed\n\n- Add await to async semaphore release() coroutine (#197)\n- Drop incorrect curio classifier (#192)\n\n## 0.11.0 (September 22nd, 2020)\n\nThe Transport API with 0.11.0 has a couple of significant changes.\n\nFirstly we've moved changed the request interface in order to allow extensions, which will later enable us to support features\nsuch as trailing headers, HTTP/2 server push, and CONNECT/Upgrade connections.\n\nThe interface changes from:\n\n```python\ndef request(method, url, headers, stream, timeout):\n return (http_version, status_code, reason, headers, stream)\n```\n\nTo instead including an optional dictionary of extensions on the request and response:\n\n```python\ndef request(method, url, headers, stream, ext):\n return (status_code, headers, stream, ext)\n```\n\nHaving an open-ended extensions point will allow us to add later support for various optional features, that wouldn't otherwise be supported without these API changes.\n\nIn particular:\n\n* Trailing headers support.\n* HTTP/2 Server Push\n* sendfile.\n* Exposing raw connection on CONNECT, Upgrade, HTTP/2 bi-di streaming.\n* Exposing debug information out of the API, including template name, template context.\n\nCurrently extensions are limited to:\n\n* request: `timeout` - Optional. Timeout dictionary.\n* response: `http_version` - Optional. Include the HTTP version used on the response.\n* response: `reason` - Optional. Include the reason phrase used on the response. Only valid with HTTP/1.*.\n\nSee https://github.com/encode/httpx/issues/1274#issuecomment-694884553 for the history behind this.\n\nSecondly, the async version of `request` is now namespaced as `arequest`.\n\nThis allows concrete transports to support both sync and async implementations on the same class.\n\n### Added\n\n- Add curio support. (Pull #168)\n- Add anyio support, with `backend=\"anyio\"`. (Pull #169)\n\n### Changed\n\n- Update the Transport API to use 'ext' for optional extensions. (Pull #190)\n- Update the Transport API to use `.request` and `.arequest` so implementations can support both sync and async. (Pull #189)\n\n## 0.10.2 (August 20th, 2020)\n\n### Added\n\n- Added Unix Domain Socket support. (Pull #139)\n\n### Fixed\n\n- Always include the port on proxy CONNECT requests. (Pull #154)\n- Fix `max_keepalive_connections` configuration. (Pull #153)\n- Fixes behaviour in HTTP/1.1 where server disconnects can be used to signal the end of the response body. (Pull #164)\n\n## 0.10.1 (August 7th, 2020)\n\n- Include `max_keepalive_connections` on `AsyncHTTPProxy`/`SyncHTTPProxy` classes.\n\n## 0.10.0 (August 7th, 2020)\n\nThe most notable change in the 0.10.0 release is that HTTP/2 support is now fully optional.\n\nUse either `pip install httpcore` for HTTP/1.1 support only, or `pip install httpcore[http2]` for HTTP/1.1 and HTTP/2 support.\n\n### Added\n\n- HTTP/2 support becomes optional. (Pull #121, #130)\n- Add `local_address=...` support. (Pull #100, #134)\n- Add `PlainByteStream`, `IteratorByteStream`, `AsyncIteratorByteStream`. The `AsyncByteSteam` and `SyncByteStream` classes are now pure interface classes. (#133)\n- Add `LocalProtocolError`, `RemoteProtocolError` exceptions. (Pull #129)\n- Add `UnsupportedProtocol` exception. (Pull #128)\n- Add `.get_connection_info()` method. (Pull #102, #137)\n- Add better TRACE logs. (Pull #101)\n\n### Changed\n\n- `max_keepalive` is deprecated in favour of `max_keepalive_connections`. (Pull #140)\n\n### Fixed\n\n- Improve handling of server disconnects. (Pull #112)\n\n## 0.9.1 (May 27th, 2020)\n\n### Fixed\n\n- Proper host resolution for sync case, including IPv6 support. (Pull #97)\n- Close outstanding connections when connection pool is closed. (Pull #98)\n\n## 0.9.0 (May 21th, 2020)\n\n### Changed\n\n- URL port becomes an `Optional[int]` instead of `int`. (Pull #92)\n\n### Fixed\n\n- Honor HTTP/2 max concurrent streams settings. (Pull #89, #90)\n- Remove incorrect debug log. (Pull #83)\n\n## 0.8.4 (May 11th, 2020)\n\n### Added\n\n- Logging via HTTPCORE_LOG_LEVEL and HTTPX_LOG_LEVEL environment variables\nand TRACE level logging. (Pull #79)\n\n### Fixed\n\n- Reuse of connections on HTTP/2 in close concurrency situations. (Pull #81)\n\n## 0.8.3 (May 6rd, 2020)\n\n### Fixed\n\n- Include `Host` and `Accept` headers on proxy \"CONNECT\" requests.\n- De-duplicate any headers also contained in proxy_headers.\n- HTTP/2 flag not being passed down to proxy connections.\n\n## 0.8.2 (May 3rd, 2020)\n\n### Fixed\n\n- Fix connections using proxy forwarding requests not being added to the\nconnection pool properly. (Pull #70)\n\n## 0.8.1 (April 30th, 2020)\n\n### Changed\n\n- Allow inherintance of both `httpcore.AsyncByteStream`, `httpcore.SyncByteStream` without type conflicts.\n\n## 0.8.0 (April 30th, 2020)\n\n### Fixed\n\n- Fixed tunnel proxy support.\n\n### Added\n\n- New `TimeoutException` base class.\n\n## 0.7.0 (March 5th, 2020)\n\n- First integration with HTTPX.\n", + "description_content_type": "text/markdown", + "author_email": "Tom Christie ", + "classifier": [ + "Development Status :: 3 - Alpha", + "Environment :: Web Environment", + "Framework :: AsyncIO", + "Framework :: Trio", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Internet :: WWW/HTTP" + ], + "requires_dist": [ + "certifi", + "h11<0.15,>=0.13", + "anyio<5.0,>=4.0; extra == 'asyncio'", + "h2<5,>=3; extra == 'http2'", + "socksio==1.*; extra == 'socks'", + "trio<0.26.0,>=0.22.0; extra == 'trio'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://www.encode.io/httpcore", + "Homepage, https://www.encode.io/httpcore/", + "Source, https://github.com/encode/httpcore" + ], + "provides_extra": [ + "asyncio", + "http2", + "socks", + "trio" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/53/9d/40d5207db523363d9b5698f33778c18b0d591e3fdb6e0116b894b2a2491c/ipykernel-6.29.4-py3-none-any.whl", + "archive_info": { + "hash": "sha256=1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da", + "hashes": { + "sha256": "1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "ipykernel", + "version": "6.29.4", + "summary": "IPython Kernel for Jupyter", + "description": "# IPython Kernel for Jupyter\n\n[![Build Status](https://github.com/ipython/ipykernel/actions/workflows/ci.yml/badge.svg?query=branch%3Amain++)](https://github.com/ipython/ipykernel/actions/workflows/ci.yml/badge.svg?query=branch%3Amain++)\n[![Documentation Status](https://readthedocs.org/projects/ipykernel/badge/?version=latest)](http://ipykernel.readthedocs.io/en/latest/?badge=latest)\n\nThis package provides the IPython kernel for Jupyter.\n\n## Installation from source\n\n1. `git clone`\n1. `cd ipykernel`\n1. `pip install -e \".[test]\"`\n\nAfter that, all normal `ipython` commands will use this newly-installed version of the kernel.\n\n## Running tests\n\nFollow the instructions from `Installation from source`.\n\nand then from the root directory\n\n```bash\npytest\n```\n\n## Running tests with coverage\n\nFollow the instructions from `Installation from source`.\n\nand then from the root directory\n\n```bash\npytest -vv -s --cov ipykernel --cov-branch --cov-report term-missing:skip-covered --durations 10\n```\n\n## About the IPython Development Team\n\nThe IPython Development Team is the set of all contributors to the IPython project.\nThis includes all of the IPython subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttps://github.com/ipython/.\n\n## Our Copyright Policy\n\nIPython uses a shared copyright model. Each contributor maintains copyright\nover their contributions to IPython. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the IPython\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire IPython\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the IPython repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n```\n# Copyright (c) IPython Development Team.\n# Distributed under the terms of the Modified BSD License.\n```\n", + "description_content_type": "text/markdown", + "keywords": [ + "Interactive", + "Interpreter", + "Shell", + "Web" + ], + "author_email": "IPython Development Team ", + "license": "BSD 3-Clause License\n\nCopyright (c) 2015, IPython Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3" + ], + "requires_dist": [ + "appnope; platform_system == 'Darwin'", + "comm>=0.1.1", + "debugpy>=1.6.5", + "ipython>=7.23.1", + "jupyter-client>=6.1.12", + "jupyter-core!=5.0.*,>=4.12", + "matplotlib-inline>=0.1", + "nest-asyncio", + "packaging", + "psutil", + "pyzmq>=24", + "tornado>=6.1", + "traitlets>=5.4.0", + "coverage[toml]; extra == 'cov'", + "curio; extra == 'cov'", + "matplotlib; extra == 'cov'", + "pytest-cov; extra == 'cov'", + "trio; extra == 'cov'", + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinx; extra == 'docs'", + "sphinx-autodoc-typehints; extra == 'docs'", + "sphinxcontrib-github-alt; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "trio; extra == 'docs'", + "pyqt5; extra == 'pyqt5'", + "pyside6; extra == 'pyside6'", + "flaky; extra == 'test'", + "ipyparallel; extra == 'test'", + "pre-commit; extra == 'test'", + "pytest-asyncio>=0.23.5; extra == 'test'", + "pytest-cov; extra == 'test'", + "pytest-timeout; extra == 'test'", + "pytest>=7.0; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://ipython.org", + "Documentation, https://ipykernel.readthedocs.io", + "Funding, https://numfocus.org/donate", + "Source, https://github.com/ipython/ipykernel", + "Tracker, https://github.com/ipython/ipykernel/issues" + ], + "provides_extra": [ + "cov", + "docs", + "pyqt5", + "pyside6", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", + "archive_info": { + "hash": "sha256=bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", + "hashes": { + "sha256": "bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "Jinja2", + "version": "3.1.4", + "summary": "A very fast and expressive template engine.", + "description": "# Jinja\n\nJinja is a fast, expressive, extensible templating engine. Special\nplaceholders in the template allow writing code similar to Python\nsyntax. Then the template is passed data to render the final document.\n\nIt includes:\n\n- Template inheritance and inclusion.\n- Define and import macros within templates.\n- HTML templates can use autoescaping to prevent XSS from untrusted\n user input.\n- A sandboxed environment can safely render untrusted templates.\n- AsyncIO support for generating templates and calling async\n functions.\n- I18N support with Babel.\n- Templates are compiled to optimized Python code just-in-time and\n cached, or can be compiled ahead-of-time.\n- Exceptions point to the correct line in templates to make debugging\n easier.\n- Extensible filters, tests, functions, and even syntax.\n\nJinja's philosophy is that while application logic belongs in Python if\npossible, it shouldn't make the template designer's job difficult by\nrestricting functionality too much.\n\n\n## In A Nutshell\n\n.. code-block:: jinja\n\n {% extends \"base.html\" %}\n {% block title %}Members{% endblock %}\n {% block content %}\n \n {% endblock %}\n\n\n## Donate\n\nThe Pallets organization develops and supports Jinja and other popular\npackages. In order to grow the community of contributors and users, and\nallow the maintainers to devote more time to the projects, [please\ndonate today][].\n\n[please donate today]: https://palletsprojects.com/donate\n\n", + "description_content_type": "text/markdown", + "maintainer_email": "Pallets ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + "Topic :: Text Processing :: Markup :: HTML", + "Typing :: Typed" + ], + "requires_dist": [ + "MarkupSafe>=2.0", + "Babel>=2.7 ; extra == \"i18n\"" + ], + "requires_python": ">=3.7", + "project_url": [ + "Changes, https://jinja.palletsprojects.com/changes/", + "Chat, https://discord.gg/pallets", + "Documentation, https://jinja.palletsprojects.com/", + "Donate, https://palletsprojects.com/donate", + "Source, https://github.com/pallets/jinja/" + ], + "provides_extra": [ + "i18n" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl", + "archive_info": { + "hash": "sha256=4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", + "hashes": { + "sha256": "4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "jupyter_core", + "version": "5.7.2", + "summary": "Jupyter core package. A base package on which Jupyter projects rely.", + "description": "There is no reason to install this package on its own.", + "description_content_type": "text/plain", + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\n- Copyright (c) 2015-, Jupyter Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Framework :: Jupyter", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3" + ], + "requires_dist": [ + "platformdirs>=2.5", + "pywin32>=300; sys_platform == 'win32' and platform_python_implementation != 'PyPy'", + "traitlets>=5.3", + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinx-autodoc-typehints; extra == 'docs'", + "sphinxcontrib-github-alt; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "traitlets; extra == 'docs'", + "ipykernel; extra == 'test'", + "pre-commit; extra == 'test'", + "pytest-cov; extra == 'test'", + "pytest-timeout; extra == 'test'", + "pytest<8; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://jupyter.org", + "Documentation, https://jupyter-core.readthedocs.io/", + "Funding, https://numfocus.org/", + "Source, https://github.com/jupyter/jupyter_core", + "Tracker, https://github.com/jupyter/jupyter_core/issues" + ], + "provides_extra": [ + "docs", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl", + "archive_info": { + "hash": "sha256=45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", + "hashes": { + "sha256": "45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "jupyter-lsp", + "version": "2.2.5", + "summary": "Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server", + "description": "# jupyter-lsp\n\nMulti-[Language Server][language-server] WebSocket proxy for your Jupyter\n`notebook` or `lab` server. For Python 3.6+.\n\n> See the parent of this repository,\n> [jupyterlab-lsp](https://github.com/jupyter-lsp/jupyterlab-lsp) for the\n> reference client implementation for [JupyterLab][].\n\n# Language Servers\n\n`jupyter-lsp` does not come with any Language Servers! Learn more about installing\nand configuring [language servers][language servers docs]\n\n[language-server]: https://microsoft.github.io/language-server-protocol/specification\n[langserver]: https://langserver.org\n[lsp-implementations]: https://microsoft.github.io/language-server-protocol/implementors/servers\n[jupyter-lsp]: https://github.com/jupyter-lsp/jupyterlab-lsp.git\n[jupyterlab]: https://github.com/jupyterlab/jupyterlab\n[language servers docs]: https://jupyterlab-lsp.readthedocs.io/en/latest/Language%20Servers.html\n", + "description_content_type": "text/markdown", + "keywords": [ + "Interactive", + "Language Server", + "LSP" + ], + "author": "jupyter-lsp Contributors", + "author_email": "project.jupyter@gmail.com", + "license": "BSD-3-Clause", + "classifier": [ + "Framework :: Jupyter", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python" + ], + "requires_dist": [ + "jupyter-server >=1.1.2", + "importlib-metadata >=4.8.3 ; python_version < \"3.10\"" + ], + "requires_python": ">=3.8", + "project_url": [ + "Bug Tracker, https://github.com/jupyter-lsp/jupyterlab-lsp/issues", + "Documentation, https://jupyterlab-lsp.readthedocs.io/", + "Source Code, https://github.com/jupyter-lsp/jupyterlab-lsp" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/07/46/6bb926b3bf878bf687b952fb6a4c09d014b4575a25960f2cd1a61793763f/jupyter_server-2.14.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=fb6be52c713e80e004fac34b35a0990d6d36ba06fd0a2b2ed82b899143a64210", + "hashes": { + "sha256": "fb6be52c713e80e004fac34b35a0990d6d36ba06fd0a2b2ed82b899143a64210" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "jupyter_server", + "version": "2.14.0", + "summary": "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications.", + "description": "# Jupyter Server\n\n[![Build Status](https://github.com/jupyter-server/jupyter_server/actions/workflows/python-tests.yml/badge.svg?query=branch%3Amain++)](https://github.com/jupyter-server/jupyter_server/actions/workflows/python-tests.yml/badge.svg?query=branch%3Amain++)\n[![Documentation Status](https://readthedocs.org/projects/jupyter-server/badge/?version=latest)](http://jupyter-server.readthedocs.io/en/latest/?badge=latest)\n\nThe Jupyter Server provides the backend (i.e. the core services, APIs, and REST endpoints) for Jupyter web applications like Jupyter notebook, JupyterLab, and Voila.\n\nFor more information, read our [documentation here](http://jupyter-server.readthedocs.io/en/latest/?badge=latest).\n\n## Installation and Basic usage\n\nTo install the latest release locally, make sure you have\n[pip installed](https://pip.readthedocs.io/en/stable/installing/) and run:\n\n```\npip install jupyter_server\n```\n\nJupyter Server currently supports Python>=3.6 on Linux, OSX and Windows.\n\n### Versioning and Branches\n\nIf Jupyter Server is a dependency of your project/application, it is important that you pin it to a version that works for your application. Currently, Jupyter Server only has minor and patch versions. Different minor versions likely include API-changes while patch versions do not change API.\n\nWhen a new minor version is released on PyPI, a branch for that version will be created in this repository, and the version of the main branch will be bumped to the next minor version number. That way, the main branch always reflects the latest un-released version.\n\nTo see the changes between releases, checkout the [CHANGELOG](https://github.com/jupyter/jupyter_server/blob/main/CHANGELOG.md).\n\n## Usage - Running Jupyter Server\n\n### Running in a local installation\n\nLaunch with:\n\n```\njupyter server\n```\n\n### Testing\n\nSee [CONTRIBUTING](https://github.com/jupyter-server/jupyter_server/blob/main/CONTRIBUTING.rst#running-tests).\n\n## Contributing\n\nIf you are interested in contributing to the project, see [`CONTRIBUTING.rst`](CONTRIBUTING.rst).\n\n## Team Meetings and Roadmap\n\n- When: Thursdays [8:00am, Pacific time](https://www.thetimezoneconverter.com/?t=8%3A00%20am&tz=San%20Francisco&)\n- Where: [Jovyan Zoom](https://zoom.us/my/jovyan?pwd=c0JZTHlNdS9Sek9vdzR3aTJ4SzFTQT09)\n- What: [Meeting notes](https://github.com/jupyter-server/team-compass/issues/45)\n\nSee our tentative [roadmap here](https://github.com/jupyter/jupyter_server/issues/127).\n\n## About the Jupyter Development Team\n\nThe Jupyter Development Team is the set of all contributors to the Jupyter project.\nThis includes all of the Jupyter subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttps://github.com/jupyter/.\n\n## Our Copyright Policy\n\nJupyter uses a shared copyright model. Each contributor maintains copyright\nover their contributions to Jupyter. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the Jupyter\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire Jupyter\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the Jupyter repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n```\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n```\n", + "description_content_type": "text/markdown", + "keywords": [ + "ipython", + "jupyter" + ], + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\n- Copyright (c) 2001-2015, IPython Development Team\n- Copyright (c) 2015-, Jupyter Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Framework :: Jupyter", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only" + ], + "requires_dist": [ + "anyio>=3.1.0", + "argon2-cffi>=21.1", + "jinja2>=3.0.3", + "jupyter-client>=7.4.4", + "jupyter-core!=5.0.*,>=4.12", + "jupyter-events>=0.9.0", + "jupyter-server-terminals>=0.4.4", + "nbconvert>=6.4.4", + "nbformat>=5.3.0", + "overrides>=5.0", + "packaging>=22.0", + "prometheus-client>=0.9", + "pywinpty>=2.0.1; os_name == 'nt'", + "pyzmq>=24", + "send2trash>=1.8.2", + "terminado>=0.8.3", + "tornado>=6.2.0", + "traitlets>=5.6.0", + "websocket-client>=1.7", + "ipykernel; extra == 'docs'", + "jinja2; extra == 'docs'", + "jupyter-client; extra == 'docs'", + "jupyter-server; extra == 'docs'", + "myst-parser; extra == 'docs'", + "nbformat; extra == 'docs'", + "prometheus-client; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "send2trash; extra == 'docs'", + "sphinx-autodoc-typehints; extra == 'docs'", + "sphinxcontrib-github-alt; extra == 'docs'", + "sphinxcontrib-openapi>=0.8.0; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "sphinxemoji; extra == 'docs'", + "tornado; extra == 'docs'", + "typing-extensions; extra == 'docs'", + "flaky; extra == 'test'", + "ipykernel; extra == 'test'", + "pre-commit; extra == 'test'", + "pytest-console-scripts; extra == 'test'", + "pytest-jupyter[server]>=0.7; extra == 'test'", + "pytest-timeout; extra == 'test'", + "pytest<9,>=7.0; extra == 'test'", + "requests; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://jupyter-server.readthedocs.io", + "Documentation, https://jupyter-server.readthedocs.io", + "Funding, https://numfocus.org/donate", + "Source, https://github.com/jupyter-server/jupyter_server", + "Tracker, https://github.com/jupyter-server/jupyter_server/issues" + ], + "provides_extra": [ + "docs", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/cb/46/d5ffd7c0f63db4e9f0982c3d58efeea10fc5f47e79fb328431df78843772/jupyterlab_server-2.27.2-py3-none-any.whl", + "archive_info": { + "hash": "sha256=54aa2d64fd86383b5438d9f0c032f043c4d8c0264b8af9f60bd061157466ea43", + "hashes": { + "sha256": "54aa2d64fd86383b5438d9f0c032f043c4d8c0264b8af9f60bd061157466ea43" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "jupyterlab_server", + "version": "2.27.2", + "summary": "A set of server components for JupyterLab and JupyterLab like applications.", + "description": "# jupyterlab server\n\n[![Build Status](https://github.com/jupyterlab/jupyterlab_server/workflows/Tests/badge.svg?branch=master)](https://github.com/jupyterlab/jupyterlab_server/actions?query=branch%3Amaster+workflow%3A%22Tests%22)\n[![Documentation Status](https://readthedocs.org/projects/jupyterlab-server/badge/?version=stable)](http://jupyterlab-server.readthedocs.io/en/stable/)\n\n## Motivation\n\nJupyterLab Server sits between JupyterLab and Jupyter Server, and provides a\nset of REST API handlers and utilities that are used by JupyterLab. It is a separate project in order to\naccommodate creating JupyterLab-like applications from a more limited scope.\n\n## Install\n\n`pip install jupyterlab_server`\n\nTo include optional `openapi` dependencies, use:\n\n`pip install jupyterlab_server[openapi]`\n\nTo include optional `pytest_plugin` dependencies, use:\n\n`pip install jupyterlab_server[test]`\n\n## Usage\n\nSee the full documentation for [API docs](https://jupyterlab-server.readthedocs.io/en/stable/api/index.html) and [REST endpoint descriptions](https://jupyterlab-server.readthedocs.io/en/stable/api/rest.html).\n\n## Extending the Application\n\nSubclass the `LabServerApp` and provide additional traits and handlers as appropriate for your application.\n\n## Contribution\n\nPlease see `CONTRIBUTING.md` for details.\n", + "description_content_type": "text/markdown", + "keywords": [ + "jupyter", + "jupyterlab" + ], + "author_email": "Jupyter Development Team ", + "license": "Copyright (c) 2015-2017, Project Jupyter Contributors\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Framework :: Jupyter", + "Framework :: Jupyter :: JupyterLab", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Typing :: Typed" + ], + "requires_dist": [ + "babel>=2.10", + "importlib-metadata>=4.8.3; python_version < '3.10'", + "jinja2>=3.0.3", + "json5>=0.9.0", + "jsonschema>=4.18.0", + "jupyter-server<3,>=1.21", + "packaging>=21.3", + "requests>=2.31", + "autodoc-traits; extra == 'docs'", + "jinja2<3.2.0; extra == 'docs'", + "mistune<4; extra == 'docs'", + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinx; extra == 'docs'", + "sphinx-copybutton; extra == 'docs'", + "sphinxcontrib-openapi>0.8; extra == 'docs'", + "openapi-core~=0.18.0; extra == 'openapi'", + "ruamel-yaml; extra == 'openapi'", + "hatch; extra == 'test'", + "ipykernel; extra == 'test'", + "openapi-core~=0.18.0; extra == 'test'", + "openapi-spec-validator<0.8.0,>=0.6.0; extra == 'test'", + "pytest-console-scripts; extra == 'test'", + "pytest-cov; extra == 'test'", + "pytest-jupyter[server]>=0.6.2; extra == 'test'", + "pytest-timeout; extra == 'test'", + "pytest<8,>=7.0; extra == 'test'", + "requests-mock; extra == 'test'", + "ruamel-yaml; extra == 'test'", + "sphinxcontrib-spelling; extra == 'test'", + "strict-rfc3339; extra == 'test'", + "werkzeug; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://jupyterlab-server.readthedocs.io", + "Documentation, https://jupyterlab-server.readthedocs.io", + "Funding, https://numfocus.org/donate-to-jupyter", + "Source, https://github.com/jupyterlab/jupyterlab_server", + "Tracker, https://github.com/jupyterlab/jupyterlab_server/issues" + ], + "provides_extra": [ + "docs", + "openapi", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", + "archive_info": { + "hash": "sha256=411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", + "hashes": { + "sha256": "411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "notebook_shim", + "version": "0.2.4", + "summary": "A shim layer for notebook traits and config", + "description": "# Notebook Shim\n\nThis project provides a way for JupyterLab and other frontends to switch to [Jupyter Server](https://github.com/jupyter/jupyter_server/) for their Python Web application backend.\n\n## Basic Usage\n\nInstall from PyPI:\n\n```\npip install notebook_shim\n```\n\nThis will automatically enable the extension in Jupyter Server.\n\n## Usage\n\nThis project also includes an API for shimming traits that moved from `NotebookApp` in to `ServerApp` in Jupyter Server. This can be used by applications that subclassed `NotebookApp` to leverage the Python server backend of Jupyter Notebooks. Such extensions should *now* switch to `ExtensionApp` API in Jupyter Server and add `NotebookConfigShimMixin` in their inheritance list to properly handle moved traits.\n\nFor example, an application class that previously looked like:\n\n```python\nfrom notebook.notebookapp import NotebookApp\n\nclass MyApplication(NotebookApp):\n```\n\nshould switch to look something like:\n\n```python\nfrom jupyter_server.extension.application import ExtensionApp\nfrom notebook_shim.shim import NotebookConfigShimMixin\n\nclass MyApplication(NotebookConfigShimMixin, ExtensionApp):\n```", + "description_content_type": "text/markdown", + "keywords": [ + "ipython", + "jupyter" + ], + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\nCopyright (c) 2022 Project Jupyter Contributors\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Framework :: Jupyter", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10" + ], + "requires_dist": [ + "jupyter-server<3,>=1.8", + "pytest; extra == 'test'", + "pytest-console-scripts; extra == 'test'", + "pytest-jupyter; extra == 'test'", + "pytest-tornasync; extra == 'test'" + ], + "requires_python": ">=3.7", + "provides_extra": [ + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "hashes": { + "sha256": "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "packaging", + "version": "24.0", + "summary": "Core utilities for Python packages", + "description": "packaging\n=========\n\n.. start-intro\n\nReusable core utilities for various Python Packaging\n`interoperability specifications `_.\n\nThis library provides utilities that implement the interoperability\nspecifications which have clearly one correct behaviour (eg: :pep:`440`)\nor benefit greatly from having a single shared implementation (eg: :pep:`425`).\n\n.. end-intro\n\nThe ``packaging`` project includes the following: version handling, specifiers,\nmarkers, requirements, tags, utilities.\n\nDocumentation\n-------------\n\nThe `documentation`_ provides information and the API for the following:\n\n- Version Handling\n- Specifiers\n- Markers\n- Requirements\n- Tags\n- Utilities\n\nInstallation\n------------\n\nUse ``pip`` to install these utilities::\n\n pip install packaging\n\nThe ``packaging`` library uses calendar-based versioning (``YY.N``).\n\nDiscussion\n----------\n\nIf you run into bugs, you can file them in our `issue tracker`_.\n\nYou can also join ``#pypa`` on Freenode to ask questions or get involved.\n\n\n.. _`documentation`: https://packaging.pypa.io/\n.. _`issue tracker`: https://github.com/pypa/packaging/issues\n\n\nCode of Conduct\n---------------\n\nEveryone interacting in the packaging project's codebases, issue trackers, chat\nrooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.\n\n.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md\n\nContributing\n------------\n\nThe ``CONTRIBUTING.rst`` file outlines how to contribute to this project as\nwell as how to report a potential security issue. The documentation for this\nproject also covers information about `project development`_ and `security`_.\n\n.. _`project development`: https://packaging.pypa.io/en/latest/development/\n.. _`security`: https://packaging.pypa.io/en/latest/security/\n\nProject History\n---------------\n\nPlease review the ``CHANGELOG.rst`` file or the `Changelog documentation`_ for\nrecent changes and project history.\n\n.. _`Changelog documentation`: https://packaging.pypa.io/en/latest/changelog/\n\n", + "description_content_type": "text/x-rst", + "author_email": "Donald Stufft ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Typing :: Typed" + ], + "requires_python": ">=3.7", + "project_url": [ + "Documentation, https://packaging.pypa.io/", + "Source, https://github.com/pypa/packaging" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/af/2b/4649926f17c1634d21c584cc855b5c5021f148b934919d26932a595bc034/tornado-6.4-cp38-abi3-win_amd64.whl", + "archive_info": { + "hash": "sha256=10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63", + "hashes": { + "sha256": "10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "tornado", + "version": "6.4", + "summary": "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed.", + "description": "Tornado Web Server\r\n==================\r\n\r\n.. image:: https://badges.gitter.im/Join%20Chat.svg\r\n :alt: Join the chat at https://gitter.im/tornadoweb/tornado\r\n :target: https://gitter.im/tornadoweb/tornado?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge\r\n\r\n`Tornado `_ is a Python web framework and\r\nasynchronous networking library, originally developed at `FriendFeed\r\n`_. By using non-blocking network I/O, Tornado\r\ncan scale to tens of thousands of open connections, making it ideal for\r\n`long polling `_,\r\n`WebSockets `_, and other\r\napplications that require a long-lived connection to each user.\r\n\r\nHello, world\r\n------------\r\n\r\nHere is a simple \"Hello, world\" example web app for Tornado:\r\n\r\n.. code-block:: python\r\n\r\n import asyncio\r\n import tornado\r\n\r\n class MainHandler(tornado.web.RequestHandler):\r\n def get(self):\r\n self.write(\"Hello, world\")\r\n\r\n def make_app():\r\n return tornado.web.Application([\r\n (r\"/\", MainHandler),\r\n ])\r\n\r\n async def main():\r\n app = make_app()\r\n app.listen(8888)\r\n await asyncio.Event().wait()\r\n\r\n if __name__ == \"__main__\":\r\n asyncio.run(main())\r\n\r\nThis example does not use any of Tornado's asynchronous features; for\r\nthat see this `simple chat room\r\n`_.\r\n\r\nDocumentation\r\n-------------\r\n\r\nDocumentation and links to additional resources are available at\r\nhttps://www.tornadoweb.org\r\n", + "description_content_type": "text/x-rst", + "home_page": "http://www.tornadoweb.org/", + "author": "Facebook", + "author_email": "python-tornado@googlegroups.com", + "license": "Apache-2.0", + "classifier": [ + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy" + ], + "requires_python": ">= 3.8", + "project_url": [ + "Source, https://github.com/tornadoweb/tornado" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", + "archive_info": { + "hash": "sha256=b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", + "hashes": { + "sha256": "b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "traitlets", + "version": "5.14.3", + "summary": "Traitlets Python configuration system", + "description": "# Traitlets\n\n[![Tests](https://github.com/ipython/traitlets/actions/workflows/tests.yml/badge.svg)](https://github.com/ipython/traitlets/actions/workflows/tests.yml)\n[![Documentation Status](https://readthedocs.org/projects/traitlets/badge/?version=latest)](https://traitlets.readthedocs.io/en/latest/?badge=latest)\n[![Tidelift](https://tidelift.com/subscription/pkg/pypi-traitlets)](https://tidelift.com/badges/package/pypi/traitlets)\n\n| | |\n| ------------- | ------------------------------------ |\n| **home** | https://github.com/ipython/traitlets |\n| **pypi-repo** | https://pypi.org/project/traitlets/ |\n| **docs** | https://traitlets.readthedocs.io/ |\n| **license** | Modified BSD License |\n\nTraitlets is a pure Python library enabling:\n\n- the enforcement of strong typing for attributes of Python objects\n (typed attributes are called _\"traits\"_);\n- dynamically calculated default values;\n- automatic validation and coercion of trait attributes when attempting a\n change;\n- registering for receiving notifications when trait values change;\n- reading configuring values from files or from command line\n arguments - a distinct layer on top of traitlets, so you may use\n traitlets without the configuration machinery.\n\nIts implementation relies on the [descriptor](https://docs.python.org/howto/descriptor.html)\npattern, and it is a lightweight pure-python alternative of the\n[_traits_ library](https://docs.enthought.com/traits/).\n\nTraitlets powers the configuration system of IPython and Jupyter\nand the declarative API of IPython interactive widgets.\n\n## Installation\n\nFor a local installation, make sure you have\n[pip installed](https://pip.pypa.io/en/stable/installing/) and run:\n\n```bash\npip install traitlets\n```\n\nFor a **development installation**, clone this repository, change into the\n`traitlets` root directory, and run pip:\n\n```bash\ngit clone https://github.com/ipython/traitlets.git\ncd traitlets\npip install -e .\n```\n\n## Running the tests\n\n```bash\npip install \"traitlets[test]\"\npy.test traitlets\n```\n\n## Code Styling\n\n`traitlets` has adopted automatic code formatting so you shouldn't\nneed to worry too much about your code style.\nAs long as your code is valid,\nthe pre-commit hook should take care of how it should look.\n\nTo install `pre-commit` locally, run the following::\n\n```\npip install pre-commit\npre-commit install\n```\n\nYou can invoke the pre-commit hook by hand at any time with::\n\n```\npre-commit run\n```\n\nwhich should run any autoformatting on your code\nand tell you about any errors it couldn't fix automatically.\nYou may also install [black integration](https://github.com/psf/black#editor-integration)\ninto your text editor to format code automatically.\n\nIf you have already committed files before setting up the pre-commit\nhook with `pre-commit install`, you can fix everything up using\n`pre-commit run --all-files`. You need to make the fixing commit\nyourself after that.\n\nSome of the hooks only run on CI by default, but you can invoke them by\nrunning with the `--hook-stage manual` argument.\n\n## Usage\n\nAny class with trait attributes must inherit from `HasTraits`.\nFor the list of available trait types and their properties, see the\n[Trait Types](https://traitlets.readthedocs.io/en/latest/trait_types.html)\nsection of the documentation.\n\n### Dynamic default values\n\nTo calculate a default value dynamically, decorate a method of your class with\n`@default({traitname})`. This method will be called on the instance, and\nshould return the default value. In this example, the `_username_default`\nmethod is decorated with `@default('username')`:\n\n```Python\nimport getpass\nfrom traitlets import HasTraits, Unicode, default\n\nclass Identity(HasTraits):\n username = Unicode()\n\n @default('username')\n def _username_default(self):\n return getpass.getuser()\n```\n\n### Callbacks when a trait attribute changes\n\nWhen a trait changes, an application can follow this trait change with\nadditional actions.\n\nTo do something when a trait attribute is changed, decorate a method with\n[`traitlets.observe()`](https://traitlets.readthedocs.io/en/latest/api.html?highlight=observe#traitlets.observe).\nThe method will be called with a single argument, a dictionary which contains\nan owner, new value, old value, name of the changed trait, and the event type.\n\nIn this example, the `_num_changed` method is decorated with `` @observe(`num`) ``:\n\n```Python\nfrom traitlets import HasTraits, Integer, observe\n\nclass TraitletsExample(HasTraits):\n num = Integer(5, help=\"a number\").tag(config=True)\n\n @observe('num')\n def _num_changed(self, change):\n print(\"{name} changed from {old} to {new}\".format(**change))\n```\n\nand is passed the following dictionary when called:\n\n```Python\n{\n 'owner': object, # The HasTraits instance\n 'new': 6, # The new value\n 'old': 5, # The old value\n 'name': \"foo\", # The name of the changed trait\n 'type': 'change', # The event type of the notification, usually 'change'\n}\n```\n\n### Validation and coercion\n\nEach trait type (`Int`, `Unicode`, `Dict` etc.) may have its own validation or\ncoercion logic. In addition, we can register custom cross-validators\nthat may depend on the state of other attributes. For example:\n\n```Python\nfrom traitlets import HasTraits, TraitError, Int, Bool, validate\n\nclass Parity(HasTraits):\n value = Int()\n parity = Int()\n\n @validate('value')\n def _valid_value(self, proposal):\n if proposal['value'] % 2 != self.parity:\n raise TraitError('value and parity should be consistent')\n return proposal['value']\n\n @validate('parity')\n def _valid_parity(self, proposal):\n parity = proposal['value']\n if parity not in [0, 1]:\n raise TraitError('parity should be 0 or 1')\n if self.value % 2 != parity:\n raise TraitError('value and parity should be consistent')\n return proposal['value']\n\nparity_check = Parity(value=2)\n\n# Changing required parity and value together while holding cross validation\nwith parity_check.hold_trait_notifications():\n parity_check.value = 1\n parity_check.parity = 1\n```\n\nHowever, we **recommend** that custom cross-validators don't modify the state\nof the HasTraits instance.\n\n## About the IPython Development Team\n\nThe IPython Development Team is the set of all contributors to the IPython project.\nThis includes all of the IPython subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttps://github.com/jupyter/.\n\n## Our Copyright Policy\n\nIPython uses a shared copyright model. Each contributor maintains copyright\nover their contributions to IPython. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the IPython\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire IPython\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the IPython repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n```\n# Copyright (c) IPython Development Team.\n# Distributed under the terms of the Modified BSD License.\n```\n", + "description_content_type": "text/markdown", + "keywords": [ + "Interactive", + "Interpreter", + "Shell", + "Web" + ], + "author_email": "IPython Development Team ", + "license": "BSD 3-Clause License\n\n- Copyright (c) 2001-, IPython Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Framework :: IPython", + "Framework :: Jupyter", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Typing :: Typed" + ], + "requires_dist": [ + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinx; extra == 'docs'", + "argcomplete>=3.0.3; extra == 'test'", + "mypy>=1.7.0; extra == 'test'", + "pre-commit; extra == 'test'", + "pytest-mock; extra == 'test'", + "pytest-mypy-testing; extra == 'test'", + "pytest<8.2,>=7.0; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://github.com/ipython/traitlets", + "Documentation, https://traitlets.readthedocs.io", + "Source, https://github.com/ipython/traitlets", + "Funding, https://numfocus.org", + "Tracker, https://github.com/ipython/traitlets/issues" + ], + "provides_extra": [ + "docs", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", + "hashes": { + "sha256": "048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "anyio", + "version": "4.3.0", + "summary": "High level compatibility layer for multiple asynchronous event loop implementations", + "description": ".. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg\n :target: https://github.com/agronholm/anyio/actions/workflows/test.yml\n :alt: Build Status\n.. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master\n :target: https://coveralls.io/github/agronholm/anyio?branch=master\n :alt: Code Coverage\n.. image:: https://readthedocs.org/projects/anyio/badge/?version=latest\n :target: https://anyio.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation\n.. image:: https://badges.gitter.im/gitterHQ/gitter.svg\n :target: https://gitter.im/python-trio/AnyIO\n :alt: Gitter chat\n\nAnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or\ntrio_. It implements trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony\nwith the native SC of trio itself.\n\nApplications and libraries written against AnyIO's API will run unmodified on either asyncio_ or\ntrio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full\nrefactoring necessary. It will blend in with the native libraries of your chosen backend.\n\nDocumentation\n-------------\n\nView full documentation at: https://anyio.readthedocs.io/\n\nFeatures\n--------\n\nAnyIO offers the following functionality:\n\n* Task groups (nurseries_ in trio terminology)\n* High-level networking (TCP, UDP and UNIX sockets)\n\n * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python\n 3.8)\n * async/await style UDP sockets (unlike asyncio where you still have to use Transports and\n Protocols)\n\n* A versatile API for byte streams and object streams\n* Inter-task synchronization and communication (locks, conditions, events, semaphores, object\n streams)\n* Worker threads\n* Subprocesses\n* Asynchronous file I/O (using worker threads)\n* Signal handling\n\nAnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures.\nIt even works with the popular Hypothesis_ library.\n\n.. _asyncio: https://docs.python.org/3/library/asyncio.html\n.. _trio: https://github.com/python-trio/trio\n.. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency\n.. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning\n.. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs\n.. _pytest: https://docs.pytest.org/en/latest/\n.. _Hypothesis: https://hypothesis.works/\n", + "description_content_type": "text/x-rst", + "author_email": "Alex Grönholm ", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Framework :: AnyIO", + "Typing :: Typed", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" + ], + "requires_dist": [ + "idna >=2.8", + "sniffio >=1.1", + "exceptiongroup >=1.0.2 ; python_version < \"3.11\"", + "typing-extensions >=4.1 ; python_version < \"3.11\"", + "packaging ; extra == 'doc'", + "Sphinx >=7 ; extra == 'doc'", + "sphinx-rtd-theme ; extra == 'doc'", + "sphinx-autodoc-typehints >=1.2.0 ; extra == 'doc'", + "anyio[trio] ; extra == 'test'", + "coverage[toml] >=7 ; extra == 'test'", + "exceptiongroup >=1.2.0 ; extra == 'test'", + "hypothesis >=4.0 ; extra == 'test'", + "psutil >=5.9 ; extra == 'test'", + "pytest >=7.0 ; extra == 'test'", + "pytest-mock >=3.6.1 ; extra == 'test'", + "trustme ; extra == 'test'", + "uvloop >=0.17 ; (platform_python_implementation == \"CPython\" and platform_system != \"Windows\") and extra == 'test'", + "trio >=0.23 ; extra == 'trio'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://anyio.readthedocs.io/en/latest/", + "Changelog, https://anyio.readthedocs.io/en/stable/versionhistory.html", + "Source code, https://github.com/agronholm/anyio", + "Issue tracker, https://github.com/agronholm/anyio/issues" + ], + "provides_extra": [ + "doc", + "test", + "trio" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea", + "hashes": { + "sha256": "c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "argon2-cffi", + "version": "23.1.0", + "summary": "Argon2 for Python", + "description": "# *argon2-cffi*: Argon2 for Python\n\n\n[Argon2](https://github.com/p-h-c/phc-winner-argon2) won the [Password Hashing Competition](https://www.password-hashing.net/) and *argon2-cffi* is the simplest way to use it in Python:\n\n```pycon\n>>> from argon2 import PasswordHasher\n>>> ph = PasswordHasher()\n>>> hash = ph.hash(\"correct horse battery staple\")\n>>> hash # doctest: +SKIP\n'$argon2id$v=19$m=65536,t=3,p=4$MIIRqgvgQbgj220jfp0MPA$YfwJSVjtjSU0zzV/P3S9nnQ/USre2wvJMjfCIjrTQbg'\n>>> ph.verify(hash, \"correct horse battery staple\")\nTrue\n>>> ph.check_needs_rehash(hash)\nFalse\n>>> ph.verify(hash, \"Tr0ub4dor&3\")\nTraceback (most recent call last):\n ...\nargon2.exceptions.VerifyMismatchError: The password does not match the supplied hash\n\n```\n\n\n## Project Links\n\n- [**PyPI**](https://pypi.org/project/argon2-cffi/)\n- [**GitHub**](https://github.com/hynek/argon2-cffi)\n- [**Documentation**](https://argon2-cffi.readthedocs.io/)\n- [**Changelog**](https://github.com/hynek/argon2-cffi/blob/main/CHANGELOG.md)\n- [**Funding**](https://hynek.me/say-thanks/)\n- The low-level Argon2 CFFI bindings are maintained in the separate [*argon2-cffi-bindings*](https://github.com/hynek/argon2-cffi-bindings) project.\n\n## Release Information\n\n### Removed\n\n- Python 3.6 is not supported anymore.\n\n\n### Deprecated\n\n- The `InvalidHash` exception is deprecated in favor of `InvalidHashError`.\n No plans for removal currently exist and the names can (but shouldn't) be used interchangeably.\n\n- `argon2.hash_password()`, `argon2.hash_password_raw()`, and `argon2.verify_password()` that have been soft-deprecated since 2016 are now hard-deprecated.\n They now raise `DeprecationWarning`s and will be removed in 2024.\n\n\n### Added\n\n- Official support for Python 3.11 and 3.12.\n No code changes were necessary.\n\n- `argon2.exceptions.InvalidHashError` as a replacement for `InvalidHash`.\n\n- *salt* parameter to `argon2.PasswordHasher.hash()` to allow for custom salts.\n This is only useful for specialized use-cases -- leave it on None unless you know exactly what you are doing.\n [#153](https://github.com/hynek/argon2-cffi/pull/153)\n\n\n---\n\n[→ Full Changelog](https://github.com/hynek/argon2-cffi/blob/main/CHANGELOG.md)\n\n\n## Credits\n\n*argon2-cffi* is maintained by [Hynek Schlawack](https://hynek.me/).\n\nThe development is kindly supported by my employer [Variomedia AG](https://www.variomedia.de/), *argon2-cffi* [Tidelift subscribers](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek), and my amazing [GitHub Sponsors](https://github.com/sponsors/hynek).\n\n\n## *argon2-cffi* for Enterprise\n\nAvailable as part of the Tidelift Subscription.\n\nThe maintainers of *argon2-cffi* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open-source packages you use to build your applications.\nSave time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.\n[Learn more.](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek)\n", + "description_content_type": "text/markdown", + "keywords": [ + "hash", + "hashing", + "password", + "security" + ], + "author_email": "Hynek Schlawack ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Security :: Cryptography", + "Topic :: Software Development :: Libraries :: Python Modules" + ], + "requires_dist": [ + "argon2-cffi-bindings", + "typing-extensions; python_version < '3.8'", + "argon2-cffi[tests,typing]; extra == 'dev'", + "tox>4; extra == 'dev'", + "furo; extra == 'docs'", + "myst-parser; extra == 'docs'", + "sphinx; extra == 'docs'", + "sphinx-copybutton; extra == 'docs'", + "sphinx-notfound-page; extra == 'docs'", + "hypothesis; extra == 'tests'", + "pytest; extra == 'tests'", + "mypy; extra == 'typing'" + ], + "requires_python": ">=3.7", + "project_url": [ + "Documentation, https://argon2-cffi.readthedocs.io/", + "Changelog, https://github.com/hynek/argon2-cffi/blob/main/CHANGELOG.md", + "GitHub, https://github.com/hynek/argon2-cffi", + "Funding, https://github.com/sponsors/hynek", + "Tidelift, https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek" + ], + "provides_extra": [ + "dev", + "docs", + "tests", + "typing" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/27/45/377f7e32a5c93d94cd56542349b34efab5ca3f9e2fd5a68c5e93169aa32d/Babel-2.15.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb", + "hashes": { + "sha256": "08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "Babel", + "version": "2.15.0", + "summary": "Internationalization utilities", + "description": "A collection of tools for internationalizing Python applications.\n", + "home_page": "https://babel.pocoo.org/", + "author": "Armin Ronacher", + "author_email": "armin.ronacher@active-4.com", + "maintainer": "Aarni Koskela", + "maintainer_email": "akx@iki.fi", + "license": "BSD-3-Clause", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development :: Libraries :: Python Modules" + ], + "requires_dist": [ + "pytz >=2015.7 ; python_version < \"3.9\"", + "pytest >=6.0 ; extra == 'dev'", + "pytest-cov ; extra == 'dev'", + "freezegun ~=1.0 ; extra == 'dev'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Source, https://github.com/python-babel/babel" + ], + "provides_extra": [ + "dev" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", + "archive_info": { + "hash": "sha256=e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", + "hashes": { + "sha256": "e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "comm", + "version": "0.2.2", + "summary": "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc.", + "description": "# Comm\n\nIt provides a way to register a Kernel Comm implementation, as per the Jupyter kernel protocol.\nIt also provides a base Comm implementation and a default CommManager that can be used.\n\n## Register a comm implementation in the kernel:\n\n### Case 1: Using the default CommManager and the BaseComm implementations\n\nWe provide default implementations for usage in IPython:\n\n```python\nimport comm\n\n\nclass MyCustomComm(comm.base_comm.BaseComm):\n def publish_msg(self, msg_type, data=None, metadata=None, buffers=None, **keys):\n # TODO implement the logic for sending comm messages through the iopub channel\n pass\n\n\ncomm.create_comm = MyCustomComm\n```\n\nThis is typically what ipykernel and JupyterLite's pyolite kernel will do.\n\n### Case 2: Providing your own comm manager creation implementation\n\n```python\nimport comm\n\ncomm.create_comm = custom_create_comm\ncomm.get_comm_manager = custom_comm_manager_getter\n```\n\nThis is typically what xeus-python does (it has its own manager implementation using xeus's C++ messaging logic).\n\n## Comm users\n\nLibraries like ipywidgets can then use the comms implementation that has been registered by the kernel:\n\n```python\nfrom comm import create_comm, get_comm_manager\n\n# Create a comm\ncomm_manager = get_comm_manager()\ncomm = create_comm()\n\ncomm_manager.register_comm(comm)\n```\n", + "description_content_type": "text/markdown", + "keywords": [ + "ipykernel", + "jupyter", + "xeus-python" + ], + "author": "Jupyter contributors", + "license": "BSD 3-Clause License\n\nCopyright (c) 2022, Jupyter\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Framework :: Jupyter", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3" + ], + "requires_dist": [ + "traitlets>=4", + "pytest; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://github.com/ipython/comm" + ], + "provides_extra": [ + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/f5/6d/d4e819e7e8a9f946eb1ce51492fbe8f8d03ad033f233096da864a5262084/debugpy-1.8.1-cp312-cp312-win_amd64.whl", + "archive_info": { + "hash": "sha256=edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98", + "hashes": { + "sha256": "edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "debugpy", + "version": "1.8.1", + "summary": "An implementation of the Debug Adapter Protocol for Python", + "description": "debugpy is an implementation of the Debug Adapter Protocol for Python.\r\n\r\nThe source code and the issue tracker is [hosted on GitHub](https://github.com/microsoft/debugpy/).\r\n", + "description_content_type": "text/markdown", + "home_page": "https://aka.ms/debugpy", + "author": "Microsoft Corporation", + "author_email": "ptvshelp@microsoft.com", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Debuggers", + "Operating System :: Microsoft :: Windows", + "Operating System :: MacOS", + "Operating System :: POSIX", + "License :: OSI Approved :: MIT License" + ], + "requires_python": ">=3.8", + "project_url": [ + "Source, https://github.com/microsoft/debugpy" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/e5/3e/741d8c82801c347547f8a2a06aa57dbb1992be9e948df2ea0eda2c8b79e8/idna-3.7-py3-none-any.whl", + "archive_info": { + "hash": "sha256=82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0", + "hashes": { + "sha256": "82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "idna", + "version": "3.7", + "summary": "Internationalized Domain Names in Applications (IDNA)", + "description": "Internationalized Domain Names in Applications (IDNA)\n=====================================================\n\nSupport for the Internationalized Domain Names in\nApplications (IDNA) protocol as specified in `RFC 5891\n`_. This is the latest version of\nthe protocol and is sometimes referred to as “IDNA 2008”.\n\nThis library also provides support for Unicode Technical\nStandard 46, `Unicode IDNA Compatibility Processing\n`_.\n\nThis acts as a suitable replacement for the “encodings.idna”\nmodule that comes with the Python standard library, but which\nonly supports the older superseded IDNA specification (`RFC 3490\n`_).\n\nBasic functions are simply executed:\n\n.. code-block:: pycon\n\n >>> import idna\n >>> idna.encode('ドメイン.テスト')\n b'xn--eckwd4c7c.xn--zckzah'\n >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah'))\n ドメイン.テスト\n\n\nInstallation\n------------\n\nThis package is available for installation from PyPI:\n\n.. code-block:: bash\n\n $ python3 -m pip install idna\n\n\nUsage\n-----\n\nFor typical usage, the ``encode`` and ``decode`` functions will take a\ndomain name argument and perform a conversion to A-labels or U-labels\nrespectively.\n\n.. code-block:: pycon\n\n >>> import idna\n >>> idna.encode('ドメイン.テスト')\n b'xn--eckwd4c7c.xn--zckzah'\n >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah'))\n ドメイン.テスト\n\nYou may use the codec encoding and decoding methods using the\n``idna.codec`` module:\n\n.. code-block:: pycon\n\n >>> import idna.codec\n >>> print('домен.испытание'.encode('idna2008'))\n b'xn--d1acufc.xn--80akhbyknj4f'\n >>> print(b'xn--d1acufc.xn--80akhbyknj4f'.decode('idna2008'))\n домен.испытание\n\nConversions can be applied at a per-label basis using the ``ulabel`` or\n``alabel`` functions if necessary:\n\n.. code-block:: pycon\n\n >>> idna.alabel('测试')\n b'xn--0zwm56d'\n\nCompatibility Mapping (UTS #46)\n+++++++++++++++++++++++++++++++\n\nAs described in `RFC 5895 `_, the\nIDNA specification does not normalize input from different potential\nways a user may input a domain name. This functionality, known as\na “mapping”, is considered by the specification to be a local\nuser-interface issue distinct from IDNA conversion functionality.\n\nThis library provides one such mapping that was developed by the\nUnicode Consortium. Known as `Unicode IDNA Compatibility Processing\n`_, it provides for both a regular\nmapping for typical applications, as well as a transitional mapping to\nhelp migrate from older IDNA 2003 applications.\n\nFor example, “Königsgäßchen” is not a permissible label as *LATIN\nCAPITAL LETTER K* is not allowed (nor are capital letters in general).\nUTS 46 will convert this into lower case prior to applying the IDNA\nconversion.\n\n.. code-block:: pycon\n\n >>> import idna\n >>> idna.encode('Königsgäßchen')\n ...\n idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed\n >>> idna.encode('Königsgäßchen', uts46=True)\n b'xn--knigsgchen-b4a3dun'\n >>> print(idna.decode('xn--knigsgchen-b4a3dun'))\n königsgäßchen\n\nTransitional processing provides conversions to help transition from\nthe older 2003 standard to the current standard. For example, in the\noriginal IDNA specification, the *LATIN SMALL LETTER SHARP S* (ß) was\nconverted into two *LATIN SMALL LETTER S* (ss), whereas in the current\nIDNA specification this conversion is not performed.\n\n.. code-block:: pycon\n\n >>> idna.encode('Königsgäßchen', uts46=True, transitional=True)\n 'xn--knigsgsschen-lcb0w'\n\nImplementers should use transitional processing with caution, only in\nrare cases where conversion from legacy labels to current labels must be\nperformed (i.e. IDNA implementations that pre-date 2008). For typical\napplications that just need to convert labels, transitional processing\nis unlikely to be beneficial and could produce unexpected incompatible\nresults.\n\n``encodings.idna`` Compatibility\n++++++++++++++++++++++++++++++++\n\nFunction calls from the Python built-in ``encodings.idna`` module are\nmapped to their IDNA 2008 equivalents using the ``idna.compat`` module.\nSimply substitute the ``import`` clause in your code to refer to the new\nmodule name.\n\nExceptions\n----------\n\nAll errors raised during the conversion following the specification\nshould raise an exception derived from the ``idna.IDNAError`` base\nclass.\n\nMore specific exceptions that may be generated as ``idna.IDNABidiError``\nwhen the error reflects an illegal combination of left-to-right and\nright-to-left characters in a label; ``idna.InvalidCodepoint`` when\na specific codepoint is an illegal character in an IDN label (i.e.\nINVALID); and ``idna.InvalidCodepointContext`` when the codepoint is\nillegal based on its positional context (i.e. it is CONTEXTO or CONTEXTJ\nbut the contextual requirements are not satisfied.)\n\nBuilding and Diagnostics\n------------------------\n\nThe IDNA and UTS 46 functionality relies upon pre-calculated lookup\ntables for performance. These tables are derived from computing against\neligibility criteria in the respective standards. These tables are\ncomputed using the command-line script ``tools/idna-data``.\n\nThis tool will fetch relevant codepoint data from the Unicode repository\nand perform the required calculations to identify eligibility. There are\nthree main modes:\n\n* ``idna-data make-libdata``. Generates ``idnadata.py`` and\n ``uts46data.py``, the pre-calculated lookup tables used for IDNA and\n UTS 46 conversions. Implementers who wish to track this library against\n a different Unicode version may use this tool to manually generate a\n different version of the ``idnadata.py`` and ``uts46data.py`` files.\n\n* ``idna-data make-table``. Generate a table of the IDNA disposition\n (e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix\n B.1 of RFC 5892 and the pre-computed tables published by `IANA\n `_.\n\n* ``idna-data U+0061``. Prints debugging output on the various\n properties associated with an individual Unicode codepoint (in this\n case, U+0061), that are used to assess the IDNA and UTS 46 status of a\n codepoint. This is helpful in debugging or analysis.\n\nThe tool accepts a number of arguments, described using ``idna-data\n-h``. Most notably, the ``--version`` argument allows the specification\nof the version of Unicode to be used in computing the table data. For\nexample, ``idna-data --version 9.0.0 make-libdata`` will generate\nlibrary data against Unicode 9.0.0.\n\n\nAdditional Notes\n----------------\n\n* **Packages**. The latest tagged release version is published in the\n `Python Package Index `_.\n\n* **Version support**. This library supports Python 3.5 and higher.\n As this library serves as a low-level toolkit for a variety of\n applications, many of which strive for broad compatibility with older\n Python versions, there is no rush to remove older interpreter support.\n Removing support for older versions should be well justified in that the\n maintenance burden has become too high.\n\n* **Python 2**. Python 2 is supported by version 2.x of this library.\n While active development of the version 2.x series has ended, notable\n issues being corrected may be backported to 2.x. Use \"idna<3\" in your\n requirements file if you need this library for a Python 2 application.\n\n* **Testing**. The library has a test suite based on each rule of the\n IDNA specification, as well as tests that are provided as part of the\n Unicode Technical Standard 46, `Unicode IDNA Compatibility Processing\n `_.\n\n* **Emoji**. It is an occasional request to support emoji domains in\n this library. Encoding of symbols like emoji is expressly prohibited by\n the technical standard IDNA 2008 and emoji domains are broadly phased\n out across the domain industry due to associated security risks. For\n now, applications that need to support these non-compliant labels\n may wish to consider trying the encode/decode operation in this library\n first, and then falling back to using `encodings.idna`. See `the Github\n project `_ for more discussion.\n\n", + "description_content_type": "text/x-rst", + "author_email": "Kim Davies ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Internet :: Name Service (DNS)", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Utilities" + ], + "requires_python": ">=3.5", + "project_url": [ + "Changelog, https://github.com/kjd/idna/blob/master/HISTORY.rst", + "Issue tracker, https://github.com/kjd/idna/issues", + "Source, https://github.com/kjd/idna" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/71/1b/c7bbd3e03ee6f3580a8afbdf8d6fd38279da03bd5c4bc431907ea3246f9a/ipython-8.24.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=d7bf2f6c4314984e3e02393213bab8703cf163ede39672ce5918c51fe253a2a3", + "hashes": { + "sha256": "d7bf2f6c4314984e3e02393213bab8703cf163ede39672ce5918c51fe253a2a3" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "ipython", + "version": "8.24.0", + "platform": [ + "Linux", + "Mac OSX", + "Windows" + ], + "summary": "IPython: Productive Interactive Computing", + "description": "IPython provides a rich toolkit to help you make the most out of using Python\ninteractively. Its main components are:\n\n * A powerful interactive Python shell\n * A `Jupyter `_ kernel to work with Python code in Jupyter\n notebooks and other interactive frontends.\n\nThe enhanced interactive Python shells have the following main features:\n\n * Comprehensive object introspection.\n\n * Input history, persistent across sessions.\n\n * Caching of output results during a session with automatically generated\n references.\n\n * Extensible tab completion, with support by default for completion of python\n variables and keywords, filenames and function keywords.\n\n * Extensible system of 'magic' commands for controlling the environment and\n performing many tasks related either to IPython or the operating system.\n\n * A rich configuration system with easy switching between different setups\n (simpler than changing $PYTHONSTARTUP environment variables every time).\n\n * Session logging and reloading.\n\n * Extensible syntax processing for special purpose situations.\n\n * Access to the system shell with user-extensible alias system.\n\n * Easily embeddable in other Python programs and GUIs.\n\n * Integrated access to the pdb debugger and the Python profiler.\n\nThe latest development version is always available from IPython's `GitHub\nsite `_.\n", + "description_content_type": "text/x-rst", + "keywords": [ + "Interactive", + "Interpreter", + "Shell", + "Embedding" + ], + "author": "The IPython Development Team", + "author_email": "ipython-dev@python.org", + "license": "BSD-3-Clause", + "classifier": [ + "Framework :: IPython", + "Framework :: Jupyter", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Topic :: System :: Shells" + ], + "requires_dist": [ + "decorator", + "jedi >=0.16", + "matplotlib-inline", + "prompt-toolkit <3.1.0,>=3.0.41", + "pygments >=2.4.0", + "stack-data", + "traitlets >=5.13.0", + "exceptiongroup ; python_version < \"3.11\"", + "typing-extensions >=4.6 ; python_version < \"3.12\"", + "pexpect >4.3 ; sys_platform != \"win32\" and sys_platform != \"emscripten\"", + "colorama ; sys_platform == \"win32\"", + "ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole] ; extra == 'all'", + "ipython[test,test_extra] ; extra == 'all'", + "black ; extra == 'black'", + "ipykernel ; extra == 'doc'", + "setuptools >=18.5 ; extra == 'doc'", + "sphinx >=1.3 ; extra == 'doc'", + "sphinx-rtd-theme ; extra == 'doc'", + "sphinxcontrib-jquery ; extra == 'doc'", + "docrepr ; extra == 'doc'", + "matplotlib ; extra == 'doc'", + "stack-data ; extra == 'doc'", + "typing-extensions ; extra == 'doc'", + "exceptiongroup ; extra == 'doc'", + "ipython[test] ; extra == 'doc'", + "ipykernel ; extra == 'kernel'", + "matplotlib ; extra == 'matplotlib'", + "nbconvert ; extra == 'nbconvert'", + "nbformat ; extra == 'nbformat'", + "ipywidgets ; extra == 'notebook'", + "notebook ; extra == 'notebook'", + "ipyparallel ; extra == 'parallel'", + "qtconsole ; extra == 'qtconsole'", + "pytest ; extra == 'test'", + "pytest-asyncio <0.22 ; extra == 'test'", + "testpath ; extra == 'test'", + "pickleshare ; extra == 'test'", + "ipython[test] ; extra == 'test_extra'", + "curio ; extra == 'test_extra'", + "matplotlib !=3.2.0 ; extra == 'test_extra'", + "nbformat ; extra == 'test_extra'", + "numpy >=1.23 ; extra == 'test_extra'", + "pandas ; extra == 'test_extra'", + "trio ; extra == 'test_extra'" + ], + "requires_python": ">=3.10", + "project_url": [ + "Homepage, https://ipython.org", + "Documentation, https://ipython.readthedocs.io/", + "Funding, https://numfocus.org/", + "Source, https://github.com/ipython/ipython", + "Tracker, https://github.com/ipython/ipython/issues" + ], + "provides_extra": [ + "all", + "black", + "doc", + "kernel", + "matplotlib", + "nbconvert", + "nbformat", + "notebook", + "parallel", + "qtconsole", + "terminal", + "test", + "test_extra" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/8a/3c/4f8791ee53ab9eeb0b022205aa79387119a74cc9429582ce04098e6fc540/json5-0.9.25-py3-none-any.whl", + "archive_info": { + "hash": "sha256=34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f", + "hashes": { + "sha256": "34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "json5", + "version": "0.9.25", + "summary": "A Python implementation of the JSON5 data format.", + "description": "# pyjson5\n\nA Python implementation of the JSON5 data format.\n\n[JSON5](https://json5.org) extends the\n[JSON](http://www.json.org) data interchange format to make it\nslightly more usable as a configuration language:\n\n* JavaScript-style comments (both single and multi-line) are legal.\n\n* Object keys may be unquoted if they are legal ECMAScript identifiers\n\n* Objects and arrays may end with trailing commas.\n\n* Strings can be single-quoted, and multi-line string literals are allowed.\n\nThere are a few other more minor extensions to JSON; see the above page for\nthe full details.\n\nThis project implements a reader and writer implementation for Python;\nwhere possible, it mirrors the\n[standard Python JSON API](https://docs.python.org/library/json.html)\npackage for ease of use.\n\nThere is one notable difference from the JSON api: the `load()` and\n`loads()` methods support optionally checking for (and rejecting) duplicate\nobject keys; pass `allow_duplicate_keys=False` to do so (duplicates are\nallowed by default).\n\nThis is an early release. It has been reasonably well-tested, but it is\n**SLOW**. It can be 1000-6000x slower than the C-optimized JSON module,\nand is 200x slower (or more) than the pure Python JSON module.\n\n**Please Note:** This library only handles JSON5 documents, it does not\nallow you to read arbitrary JavaScript. For example, bare integers can\nbe legal object keys in JavaScript, but they aren't in JSON5.\n\n## Known issues\n\n* Did I mention that it is **SLOW**?\n\n* The implementation follows Python3's `json` implementation where\n possible. This means that the `encoding` method to `dump()` is\n ignored, and unicode strings are always returned.\n\n* The `cls` keyword argument that `json.load()`/`json.loads()` accepts\n to specify a custom subclass of ``JSONDecoder`` is not and will not be\n supported, because this implementation uses a completely different\n approach to parsing strings and doesn't have anything like the\n `JSONDecoder` class.\n\n* The `cls` keyword argument that `json.dump()`/`json.dumps()` accepts\n is also not supported, for consistency with `json5.load()`. The `default`\n keyword *is* supported, though, and might be able to serve as a\n workaround.\n\n## Running the tests\nTo run the tests, setup a venv and install the required dependencies with\n`pip install -e '.[dev]'`, then run the tests with `python setup.py test`.\n\n## Updating the packages\n\n```\n# Install the build packages if need be\n$ python3 -m pip install build twine\n\n# Build the distribution packages in //dist\n# (a wheel and a tarball by default)\n$ python3 -m build\n\n# Upload the packages\n$ python3 -m twine upload dist/*\n\n(Assuming you have upload privileges to PyPI, of course.)\n```\n\n## Version History / Release Notes\n\n* v0.9.25 (2024-04-12)\n * [GitHub issue #81](https://github.com/dpranke/pyjson5/issues/81)\n Explicitly specify the directory to use for the package in\n pyproject.toml.\n* v0.9.24 (2024-03-16)\n * Update GitHub workflow config to remove unnecessary steps and\n run on pull requests as well as commits.\n * Added note about removing `hypothesize` in v0.9.23.\n * No code changes.\n* v0.9.23 (2024-03-16)\n * Lots of cleanup:\n * Removed old code needed for Python2 compatibility.\n * Removed tests using `hypothesize`. This ran model-based checks\n and didn't really add anything useful in terms of coverage to\n the test suite, and it introduced dependencies and slowed down\n the tests significantly. It was a good experiment but I think\n we're better off without it.\n * Got everything linting cleanly with pylint 3.1 and `ruff check`\n using ruff 0.3.3 (Note that commit message in 00d73a3 says pylint\n 3.11, which is a typo).\n * Code reformatted with `ruff format`\n * Added missing tests to bring coverage up to 100%.\n * Lots of minor code changes as the result of linting and coverage\n testing, but no intentional functional differences.\n* v0.9.22 (2024-03-06)\n * Attempt to fix the GitHub CI configuration now that setup.py\n is gone. Also, test on 3.12 instead of 3.11.\n * No code changes.\n* v0.9.21 (2024-03-06)\n * Moved the benchmarks/*.json data files' license information\n to //LICENSE to (hopefully) make the Google linter happy.\n* v0.9.20 (2024-03-03)\n * Added `json5.__version__` in addition to `json5.VERSION`.\n * More packaging modernization (no more setup.{cfg,py} files).\n * Mark Python3.12 as supported in project.classifiers.\n * Updated the `//run` script to use python3.\n* v0.9.19 (2024-03-03)\n * Replaced the benchmarking data files that came from chromium.org with\n three files obtained from other datasets on GitHub. Since this repo\n is vendored into the chromium/src repo it was occasionally confusing\n people who thought the data was actually used for non-benchmarking\n purposes and thus updating it for whatever reason.\n * No code changes.\n* v0.9.18 (2024-02-29)\n * Add typing information to the module. This is kind of a big change,\n but there should be no functional differences.\n* v0.9.17 (2024-02-19)\n * Move from `setup.py` to `pyproject.toml`.\n * No code changes (other than the version increasing).\n* v0.9.16 (2024-02-19)\n * Drop Python2 from `setup.py`\n * Add minimal packaging instructions to `//README.md`.\n* v0.9.15 (2024-02-19)\n * Merge in [Pull request #66](https://github.com/dpranke/pyjson5/pull/66)\n to include the tests and sample file in a source distribution.\n* v0.9.14 (2023-05-14)\n * [GitHub issue #63](https://github.com/dpranke/pyjson5/issues/63)\n Handle `+Infinity` as well as `-Infinity` and `Infinity`.\n* v0.9.13 (2023-03-16)\n * [GitHub PR #64](https://github.com/dpranke/pyjson5/pull/64)\n Remove a field from one of the JSON benchmark files to\n reduce confusion in Chromium.\n * No code changes.\n* v0.9.12 (2023-01-02)\n * Fix GitHub Actions config file to no longer test against\n Python 3.6 or 3.7. For now we will only test against an\n \"oldest\" release (3.8 in this case) and a \"current\"\n release (3.11 in this case).\n* v0.9.11 (2023-01-02)\n * [GitHub issue #60](https://github.com/dpranke/pyjson5/issues/60)\n Fixed minor Python2 compatibility issue by referring to\n `float(\"inf\")` instead of `math.inf`.\n* v0.9.10 (2022-08-18)\n * [GitHub issue #58](https://github.com/dpranke/pyjson5/issues/58)\n Updated the //README.md to be clear that parsing arbitrary JS\n code may not work.\n * Otherwise, no code changes.\n* v0.9.9 (2022-08-01)\n * [GitHub issue #57](https://github.com/dpranke/pyjson5/issues/57)\n Fixed serialization for objects that subclass `int` or `float`:\n Previously we would use the objects __str__ implementation, but\n that might result in an illegal JSON5 value if the object had\n customized __str__ to return something illegal. Instead,\n we follow the lead of the `JSON` module and call `int.__repr__`\n or `float.__repr__` directly.\n * While I was at it, I added tests for dumps(-inf) and dumps(nan)\n when those were supposed to be disallowed by `allow_nan=False`.\n* v0.9.8 (2022-05-08)\n * [GitHub issue #47](https://github.com/dpranke/pyjson5/issues/47)\n Fixed error reporting in some cases due to how parsing was handling\n nested rules in the grammar - previously the reported location for\n the error could be far away from the point where it actually happened.\n\n* v0.9.7 (2022-05-06)\n * [GitHub issue #52](https://github.com/dpranke/pyjson5/issues/52)\n Fixed behavior of `default` fn in `dump` and `dumps`. Previously\n we didn't require the function to return a string, and so we could\n end up returning something that wasn't actually valid. This change\n now matches the behavior in the `json` module. *Note: This is a\n potentially breaking change.*\n* v0.9.6 (2021-06-21)\n * Bump development status classifier to 5 - Production/Stable, which\n the library feels like it is at this point. If I do end up significantly\n reworking things to speed it up and/or to add round-trip editing,\n that'll likely be a 2.0. If this version has no reported issues,\n I'll likely promote it to 1.0.\n * Also bump the tested Python versions to 2.7, 3.8 and 3.9, though\n earlier Python3 versions will likely continue to work as well.\n * [GitHub issue #46](https://github.com/dpranke/pyjson5/issues/36)\n Fix incorrect serialization of custom subtypes\n * Make it possible to run the tests if `hypothesis` isn't installed.\n\n* v0.9.5 (2020-05-26)\n * Miscellaneous non-source cleanups in the repo, including setting\n up GitHub Actions for a CI system. No changes to the library from\n v0.9.4, other than updating the version.\n\n* v0.9.4 (2020-03-26)\n * [GitHub pull #38](https://github.com/dpranke/pyjson5/pull/38)\n Fix from fredrik@fornwall.net for dumps() crashing when passed\n an empty string as a key in an object.\n\n* v0.9.3 (2020-03-17)\n * [GitHub pull #35](https://github.com/dpranke/pyjson5/pull/35)\n Fix from pastelmind@ for dump() not passing the right args to dumps().\n * Fix from p.skouzos@novafutur.com to remove the tests directory from\n the setup call, making the package a bit smaller.\n\n* v0.9.2 (2020-03-02)\n * [GitHub pull #34](https://github.com/dpranke/pyjson5/pull/34)\n Fix from roosephu@ for a badly formatted nested list.\n\n* v0.9.1 (2020-02-09)\n * [GitHub issue #33](https://github.com/dpranke/pyjson5/issues/33):\n Fix stray trailing comma when dumping an object with an invalid key.\n\n* v0.9.0 (2020-01-30)\n * [GitHub issue #29](https://github.com/dpranke/pyjson5/issues/29):\n Fix an issue where objects keys that started with a reserved\n word were incorrectly quoted.\n * [GitHub issue #30](https://github.com/dpranke/pyjson5/issues/30):\n Fix an issue where dumps() incorrectly thought a data structure\n was cyclic in some cases.\n * [GitHub issue #32](https://github.com/dpranke/pyjson5/issues/32):\n Allow for non-string keys in dicts passed to ``dump()``/``dumps()``.\n Add an ``allow_duplicate_keys=False`` to prevent possible\n ill-formed JSON that might result.\n\n* v0.8.5 (2019-07-04)\n * [GitHub issue #25](https://github.com/dpranke/pyjson5/issues/25):\n Add LICENSE and README.md to the dist.\n * [GitHub issue #26](https://github.com/dpranke/pyjson5/issues/26):\n Fix printing of empty arrays and objects with indentation, fix\n misreporting of the position on parse failures in some cases.\n\n* v0.8.4 (2019-06-11)\n * Updated the version history, too.\n\n* v0.8.3 (2019-06-11)\n * Tweaked the README, bumped the version, forgot to update the version\n history :).\n\n* v0.8.2 (2019-06-11)\n * Actually bump the version properly, to 0.8.2.\n\n* v0.8.1 (2019-06-11)\n * Fix bug in setup.py that messed up the description. Unfortunately,\n I forgot to bump the version for this, so this also identifies as 0.8.0.\n\n* v0.8.0 (2019-06-11)\n * Add `allow_duplicate_keys=True` as a default argument to\n `json5.load()`/`json5.loads()`. If you set the key to `False`, duplicate\n keys in a single dict will be rejected. The default is set to `True`\n for compatibility with `json.load()`, earlier versions of json5, and\n because it's simply not clear if people would want duplicate checking\n enabled by default.\n\n* v0.7 (2019-03-31)\n * Changes dump()/dumps() to not quote object keys by default if they are\n legal identifiers. Passing `quote_keys=True` will turn that off\n and always quote object keys.\n * Changes dump()/dumps() to insert trailing commas after the last item\n in an array or an object if the object is printed across multiple lines\n (i.e., if `indent` is not None). Passing `trailing_commas=False` will\n turn that off.\n * The `json5.tool` command line tool now supports the `--indent`,\n `--[no-]quote-keys`, and `--[no-]trailing-commas` flags to allow\n for more control over the output, in addition to the existing\n `--as-json` flag.\n * The `json5.tool` command line tool no longer supports reading from\n multiple files, you can now only read from a single file or\n from standard input.\n * The implementation no longer relies on the standard `json` module\n for anything. The output should still match the json module (except\n as noted above) and discrepancies should be reported as bugs.\n\n* v0.6.2 (2019-03-08)\n * Fix [GitHub issue #23](https://github.com/dpranke/pyjson5/issues/23) and\n pass through unrecognized escape sequences.\n\n* v0.6.1 (2018-05-22)\n * Cleaned up a couple minor nits in the package.\n\n* v0.6.0 (2017-11-28)\n * First implementation that attempted to implement 100% of the spec.\n\n* v0.5.0 (2017-09-04)\n * First implementation that supported the full set of kwargs that\n the `json` module supports.\n", + "description_content_type": "text/markdown", + "author_email": "Dirk Pranke ", + "license": "Files: Everything except for the benchmarks/*.json files.\n\nApache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n---\n\nFile: benchmarks/64KB-min.json\n\nMIT License\n\nCopyright (c) Microsoft Corporation.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE\n\n---\n\nFile: benchmarks/bitly-usa-gov.json\n\nThe MIT License (MIT)\n\nCopyright (c) 2017 Wes McKinney\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n---\n\nFile: benchmarks/twitter.json\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Milo Yip\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" + ], + "requires_python": ">=3.8", + "project_url": [ + "Repository, https://github.com/dpranke/pyjson5", + "Issues, https://github.com/dpranke/pyjson5/issues", + "Changelog, https://github.com/dpranke/pyjson5/blob/master/README.md" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/c8/2f/324fab4be6fe37fb7b521546e8a557e6cf08c1c1b3d0b4839a00f589d9ef/jsonschema-4.22.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802", + "hashes": { + "sha256": "ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "jsonschema", + "version": "4.22.0", + "summary": "An implementation of JSON Schema validation for Python", + "description": "==========\njsonschema\n==========\n\n|PyPI| |Pythons| |CI| |ReadTheDocs| |Precommit| |Zenodo|\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/jsonschema.svg\n :alt: PyPI version\n :target: https://pypi.org/project/jsonschema/\n\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/jsonschema.svg\n :alt: Supported Python versions\n :target: https://pypi.org/project/jsonschema/\n\n.. |CI| image:: https://github.com/python-jsonschema/jsonschema/workflows/CI/badge.svg\n :alt: Build status\n :target: https://github.com/python-jsonschema/jsonschema/actions?query=workflow%3ACI\n\n.. |ReadTheDocs| image:: https://readthedocs.org/projects/python-jsonschema/badge/?version=stable&style=flat\n :alt: ReadTheDocs status\n :target: https://python-jsonschema.readthedocs.io/en/stable/\n\n.. |Precommit| image:: https://results.pre-commit.ci/badge/github/python-jsonschema/jsonschema/main.svg\n :alt: pre-commit.ci status\n :target: https://results.pre-commit.ci/latest/github/python-jsonschema/jsonschema/main\n\n.. |Zenodo| image:: https://zenodo.org/badge/3072629.svg\n :alt: Zenodo DOI\n :target: https://zenodo.org/badge/latestdoi/3072629\n\n\n``jsonschema`` is an implementation of the `JSON Schema `_ specification for Python.\n\n.. code:: python\n\n >>> from jsonschema import validate\n\n >>> # A sample schema, like what we'd get from json.load()\n >>> schema = {\n ... \"type\" : \"object\",\n ... \"properties\" : {\n ... \"price\" : {\"type\" : \"number\"},\n ... \"name\" : {\"type\" : \"string\"},\n ... },\n ... }\n\n >>> # If no exception is raised by validate(), the instance is valid.\n >>> validate(instance={\"name\" : \"Eggs\", \"price\" : 34.99}, schema=schema)\n\n >>> validate(\n ... instance={\"name\" : \"Eggs\", \"price\" : \"Invalid\"}, schema=schema,\n ... ) # doctest: +IGNORE_EXCEPTION_DETAIL\n Traceback (most recent call last):\n ...\n ValidationError: 'Invalid' is not of type 'number'\n\nIt can also be used from the command line by installing `check-jsonschema `_.\n\nFeatures\n--------\n\n* Full support for `Draft 2020-12 `_, `Draft 2019-09 `_, `Draft 7 `_, `Draft 6 `_, `Draft 4 `_ and `Draft 3 `_\n\n* `Lazy validation `_ that can iteratively report *all* validation errors.\n\n* `Programmatic querying `_ of which properties or items failed validation.\n\n\nInstallation\n------------\n\n``jsonschema`` is available on `PyPI `_. You can install using `pip `_:\n\n.. code:: bash\n\n $ pip install jsonschema\n\n\nExtras\n======\n\nTwo extras are available when installing the package, both currently related to ``format`` validation:\n\n * ``format``\n * ``format-nongpl``\n\nThey can be used when installing in order to include additional dependencies, e.g.:\n\n.. code:: bash\n\n $ pip install jsonschema'[format]'\n\nBe aware that the mere presence of these dependencies – or even the specification of ``format`` checks in a schema – do *not* activate format checks (as per the specification).\nPlease read the `format validation documentation `_ for further details.\n\nAbout\n-----\n\nI'm Julian Berman.\n\n``jsonschema`` is on `GitHub `_.\n\nGet in touch, via GitHub or otherwise, if you've got something to contribute, it'd be most welcome!\n\nYou can also generally find me on Libera (nick: ``Julian``) in various channels, including ``#python``.\n\nIf you feel overwhelmingly grateful, you can also `sponsor me `_.\n\nAnd for companies who appreciate ``jsonschema`` and its continued support and growth, ``jsonschema`` is also now supportable via `TideLift `_.\n\n\nRelease Information\n-------------------\n\nv4.22.0\n=======\n\n* Improve ``best_match`` (and thereby error messages from ``jsonschema.validate``) in cases where there are multiple *sibling* errors from applying ``anyOf`` / ``allOf`` -- i.e. when multiple elements of a JSON array have errors, we now do prefer showing errors from earlier elements rather than simply showing an error for the full array (#1250).\n* (Micro-)optimize equality checks when comparing for JSON Schema equality by first checking for object identity, as ``==`` would.\n", + "description_content_type": "text/x-rst", + "keywords": [ + "data validation", + "json", + "json schema", + "jsonschema", + "validation" + ], + "author_email": "Julian Berman ", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: File Formats :: JSON", + "Topic :: File Formats :: JSON :: JSON Schema" + ], + "requires_dist": [ + "attrs>=22.2.0", + "importlib-resources>=1.4.0; python_version < '3.9'", + "jsonschema-specifications>=2023.03.6", + "pkgutil-resolve-name>=1.3.10; python_version < '3.9'", + "referencing>=0.28.4", + "rpds-py>=0.7.1", + "fqdn; extra == 'format'", + "idna; extra == 'format'", + "isoduration; extra == 'format'", + "jsonpointer>1.13; extra == 'format'", + "rfc3339-validator; extra == 'format'", + "rfc3987; extra == 'format'", + "uri-template; extra == 'format'", + "webcolors>=1.11; extra == 'format'", + "fqdn; extra == 'format-nongpl'", + "idna; extra == 'format-nongpl'", + "isoduration; extra == 'format-nongpl'", + "jsonpointer>1.13; extra == 'format-nongpl'", + "rfc3339-validator; extra == 'format-nongpl'", + "rfc3986-validator>0.1.0; extra == 'format-nongpl'", + "uri-template; extra == 'format-nongpl'", + "webcolors>=1.11; extra == 'format-nongpl'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://github.com/python-jsonschema/jsonschema", + "Documentation, https://python-jsonschema.readthedocs.io/", + "Issues, https://github.com/python-jsonschema/jsonschema/issues/", + "Funding, https://github.com/sponsors/Julian", + "Tidelift, https://tidelift.com/subscription/pkg/pypi-jsonschema?utm_source=pypi-jsonschema&utm_medium=referral&utm_campaign=pypi-link", + "Changelog, https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst", + "Source, https://github.com/python-jsonschema/jsonschema" + ], + "provides_extra": [ + "format", + "format-nongpl" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/75/6d/d7b55b9c1ac802ab066b3e5015e90faab1fffbbd67a2af498ffc6cc81c97/jupyter_client-8.6.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f", + "hashes": { + "sha256": "3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "jupyter_client", + "version": "8.6.1", + "summary": "Jupyter protocol implementation and client libraries", + "description": "# Jupyter Client\n\n[![Build Status](https://github.com/jupyter/jupyter_client/workflows/CI/badge.svg)](https://github.com/jupyter/jupyter_client/actions)\n[![Documentation Status](https://readthedocs.org/projects/jupyter-client/badge/?version=latest)](http://jupyter-client.readthedocs.io/en/latest/?badge=latest)\n\n`jupyter_client` contains the reference implementation of the [Jupyter protocol].\nIt also provides client and kernel management APIs for working with kernels.\n\nIt also provides the `jupyter kernelspec` entrypoint\nfor installing kernelspecs for use with Jupyter frontends.\n\n## Development Setup\n\nThe [Jupyter Contributor Guides](https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html) provide extensive information on contributing code or documentation to Jupyter projects. The limited instructions below for setting up a development environment are for your convenience.\n\n## Coding\n\nYou'll need Python and `pip` on the search path. Clone the Jupyter Client git repository to your computer, for example in `/my/project/jupyter_client`\n\n```bash\ncd /my/projects/\ngit clone git@github.com:jupyter/jupyter_client.git\n```\n\nNow create an [editable install](https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs)\nand download the dependencies of code and test suite by executing:\n\n```bash\ncd /my/projects/jupyter_client/\npip install -e \".[test]\"\npytest\n```\n\nThe last command runs the test suite to verify the setup. During development, you can pass filenames to `pytest`, and it will execute only those tests.\n\n## Documentation\n\nThe documentation of Jupyter Client is generated from the files in `docs/` using Sphinx. Instructions for setting up Sphinx with a selection of optional modules are in the [Documentation Guide](https://jupyter.readthedocs.io/en/latest/contributing/docs-contributions/index.html). You'll also need the `make` command.\nFor a minimal Sphinx installation to process the Jupyter Client docs, execute:\n\n```bash\npip install \".[doc]\"\n```\n\nThe following commands build the documentation in HTML format and check for broken links:\n\n```bash\ncd /my/projects/jupyter_client/docs/\nmake html linkcheck\n```\n\nPoint your browser to the following URL to access the generated documentation:\n\n_file:///my/projects/jupyter_client/docs/\\_build/html/index.html_\n\n## Contributing\n\n`jupyter-client` has adopted automatic code formatting so you shouldn't\nneed to worry too much about your code style.\nAs long as your code is valid,\nthe pre-commit hook should take care of how it should look.\nYou can invoke the pre-commit hook by hand at any time with:\n\n```bash\npre-commit run\n```\n\nwhich should run any autoformatting on your code\nand tell you about any errors it couldn't fix automatically.\nYou may also install [black integration](https://black.readthedocs.io/en/stable/integrations/editors.html)\ninto your text editor to format code automatically.\n\nIf you have already committed files before setting up the pre-commit\nhook with `pre-commit install`, you can fix everything up using\n`pre-commit run --all-files`. You need to make the fixing commit\nyourself after that.\n\nSome of the hooks only run on CI by default, but you can invoke them by\nrunning with the `--hook-stage manual` argument.\n\n## About the Jupyter Development Team\n\nThe Jupyter Development Team is the set of all contributors to the Jupyter project.\nThis includes all of the Jupyter subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttps://github.com/jupyter/.\n\n## Our Copyright Policy\n\nJupyter uses a shared copyright model. Each contributor maintains copyright\nover their contributions to Jupyter. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the Jupyter\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire Jupyter\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the Jupyter repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n```\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n```\n\n[jupyter protocol]: https://jupyter-client.readthedocs.io/en/latest/messaging.html\n", + "description_content_type": "text/markdown", + "keywords": [ + "Interactive", + "Interpreter", + "Shell", + "Web" + ], + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\n- Copyright (c) 2001-2015, IPython Development Team\n- Copyright (c) 2015-, Jupyter Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Framework :: Jupyter", + "Intended Audience :: Developers", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3" + ], + "requires_dist": [ + "importlib-metadata>=4.8.3; python_version < '3.10'", + "jupyter-core!=5.0.*,>=4.12", + "python-dateutil>=2.8.2", + "pyzmq>=23.0", + "tornado>=6.2", + "traitlets>=5.3", + "ipykernel; extra == 'docs'", + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinx-autodoc-typehints; extra == 'docs'", + "sphinx>=4; extra == 'docs'", + "sphinxcontrib-github-alt; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "coverage; extra == 'test'", + "ipykernel>=6.14; extra == 'test'", + "mypy; extra == 'test'", + "paramiko; (sys_platform == 'win32') and extra == 'test'", + "pre-commit; extra == 'test'", + "pytest; extra == 'test'", + "pytest-cov; extra == 'test'", + "pytest-jupyter[client]>=0.4.1; extra == 'test'", + "pytest-timeout; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://jupyter.org", + "Documentation, https://jupyter-client.readthedocs.io/", + "Source, https://github.com/jupyter/jupyter_client" + ], + "provides_extra": [ + "docs", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/a5/94/059180ea70a9a326e1815176b2370da56376da347a796f8c4f0b830208ef/jupyter_events-0.10.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960", + "hashes": { + "sha256": "4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "jupyter-events", + "version": "0.10.0", + "summary": "Jupyter Event System library", + "description": "# Jupyter Events\n\n[![Build Status](https://github.com/jupyter/jupyter_events/actions/workflows/python-tests.yml/badge.svg?query=branch%3Amain++)](https://github.com/jupyter/jupyter_events/actions/workflows/python-tests.yml/badge.svg?query=branch%3Amain++)\n[![Documentation Status](https://readthedocs.org/projects/jupyter-events/badge/?version=latest)](http://jupyter-events.readthedocs.io/en/latest/?badge=latest)\n\n_An event system for Jupyter Applications and extensions._\n\nJupyter Events enables Jupyter Python Applications (e.g. Jupyter Server, JupyterLab Server, JupyterHub, etc.) to emit **events**—structured data describing things happening inside the application. Other software (e.g. client applications like JupyterLab) can _listen_ and respond to these events.\n\n## Install\n\nInstall Jupyter Events directly from PyPI:\n\n```\npip install jupyter_events\n```\n\nor conda-forge:\n\n```\nconda install -c conda-forge jupyter_events\n```\n\n## Documentation\n\nDocumentation is available at [jupyter-events.readthedocs.io](https://jupyter-events.readthedocs.io).\n\n## About the Jupyter Development Team\n\nThe Jupyter Development Team is the set of all contributors to the Jupyter project.\nThis includes all of the Jupyter subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttps://github.com/jupyter/.\n\n## Our Copyright Policy\n\nJupyter uses a shared copyright model. Each contributor maintains copyright\nover their contributions to Jupyter. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the Jupyter\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire Jupyter\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the Jupyter repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n```\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n```\n", + "description_content_type": "text/markdown", + "keywords": [ + "Jupyter", + "JupyterLab" + ], + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\n Copyright (c) 2022-, Jupyter Development Team\n\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n 3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3" + ], + "requires_dist": [ + "jsonschema[format-nongpl]>=4.18.0", + "python-json-logger>=2.0.4", + "pyyaml>=5.3", + "referencing", + "rfc3339-validator", + "rfc3986-validator>=0.1.1", + "traitlets>=5.3", + "click; extra == 'cli'", + "rich; extra == 'cli'", + "jupyterlite-sphinx; extra == 'docs'", + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "click; extra == 'test'", + "pre-commit; extra == 'test'", + "pytest-asyncio>=0.19.0; extra == 'test'", + "pytest-console-scripts; extra == 'test'", + "pytest>=7.0; extra == 'test'", + "rich; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, http://jupyter.org", + "documentation, https://jupyter-events.readthedocs.io/", + "repository, https://github.com/jupyter/jupyter_events.git", + "changelog, https://github.com/jupyter/jupyter_events/blob/main/CHANGELOG.md" + ], + "provides_extra": [ + "cli", + "docs", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", + "archive_info": { + "hash": "sha256=41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", + "hashes": { + "sha256": "41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "jupyter_server_terminals", + "version": "0.5.3", + "summary": "A Jupyter Server Extension Providing Terminals.", + "description": "# Jupyter Server Terminals\n\n[![Build Status](https://github.com/jupyter-server/jupyter_server_terminals/actions/workflows/test.yml/badge.svg?query=branch%3Amain++)](https://github.com/jupyter-server/jupyter_server_terminals/actions?query=branch%3Amain++)\n[![Documentation Status](https://readthedocs.org/projects/jupyter-server-terminals/badge/?version=latest)](http://jupyter-server-terminals.readthedocs.io/en/latest/?badge=latest)\n\nJupyter Server Terminals is a Jupyter Server Extension providing support for terminals.\n\n## Installation and Basic usage\n\nTo install the latest release locally, make sure you have\n[pip installed](https://pip.readthedocs.io/en/stable/installing/) and run:\n\n```\npip install jupyter_server_terminals\n```\n\nJupyter Server Terminals currently supports Python>=3.6 on Linux, OSX and Windows.\n\n### Testing\n\nSee [CONTRIBUTING](./CONTRIBUTING.rst#running-tests).\n\n## Contributing\n\nIf you are interested in contributing to the project, see [CONTRIBUTING](./CONTRIBUTING.rst).\n\n## About the Jupyter Development Team\n\nThe Jupyter Development Team is the set of all contributors to the Jupyter project.\nThis includes all of the Jupyter subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttps://github.com/jupyter/.\n\n## Our Copyright Policy\n\nJupyter uses a shared copyright model. Each contributor maintains copyright\nover their contributions to Jupyter. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the Jupyter\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire Jupyter\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the Jupyter repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n```\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n```\n", + "description_content_type": "text/markdown", + "keywords": [ + "ipython", + "jupyter" + ], + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\n- Copyright (c) 2021-, Jupyter Development Team\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\nAll rights reserved.\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11" + ], + "requires_dist": [ + "pywinpty>=2.0.3; os_name == 'nt'", + "terminado>=0.8.3", + "jinja2; extra == 'docs'", + "jupyter-server; extra == 'docs'", + "mistune<4.0; extra == 'docs'", + "myst-parser; extra == 'docs'", + "nbformat; extra == 'docs'", + "packaging; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinxcontrib-github-alt; extra == 'docs'", + "sphinxcontrib-openapi; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "sphinxemoji; extra == 'docs'", + "tornado; extra == 'docs'", + "jupyter-server>=2.0.0; extra == 'test'", + "pytest-jupyter[server]>=0.5.3; extra == 'test'", + "pytest-timeout; extra == 'test'", + "pytest>=7.0; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://jupyter.org" + ], + "provides_extra": [ + "docs", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", + "archive_info": { + "hash": "sha256=823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", + "hashes": { + "sha256": "823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "MarkupSafe", + "version": "2.1.5", + "summary": "Safely add untrusted strings to HTML/XML markup.", + "description": "MarkupSafe\r\n==========\r\n\r\nMarkupSafe implements a text object that escapes characters so it is\r\nsafe to use in HTML and XML. Characters that have special meanings are\r\nreplaced so that they display as the actual characters. This mitigates\r\ninjection attacks, meaning untrusted user input can safely be displayed\r\non a page.\r\n\r\n\r\nInstalling\r\n----------\r\n\r\nInstall and update using `pip`_:\r\n\r\n.. code-block:: text\r\n\r\n pip install -U MarkupSafe\r\n\r\n.. _pip: https://pip.pypa.io/en/stable/getting-started/\r\n\r\n\r\nExamples\r\n--------\r\n\r\n.. code-block:: pycon\r\n\r\n >>> from markupsafe import Markup, escape\r\n\r\n >>> # escape replaces special characters and wraps in Markup\r\n >>> escape(\"\")\r\n Markup('<script>alert(document.cookie);</script>')\r\n\r\n >>> # wrap in Markup to mark text \"safe\" and prevent escaping\r\n >>> Markup(\"Hello\")\r\n Markup('hello')\r\n\r\n >>> escape(Markup(\"Hello\"))\r\n Markup('hello')\r\n\r\n >>> # Markup is a str subclass\r\n >>> # methods and operators escape their arguments\r\n >>> template = Markup(\"Hello {name}\")\r\n >>> template.format(name='\"World\"')\r\n Markup('Hello "World"')\r\n\r\n\r\nDonate\r\n------\r\n\r\nThe Pallets organization develops and supports MarkupSafe and other\r\npopular packages. In order to grow the community of contributors and\r\nusers, and allow the maintainers to devote more time to the projects,\r\n`please donate today`_.\r\n\r\n.. _please donate today: https://palletsprojects.com/donate\r\n\r\n\r\nLinks\r\n-----\r\n\r\n- Documentation: https://markupsafe.palletsprojects.com/\r\n- Changes: https://markupsafe.palletsprojects.com/changes/\r\n- PyPI Releases: https://pypi.org/project/MarkupSafe/\r\n- Source Code: https://github.com/pallets/markupsafe/\r\n- Issue Tracker: https://github.com/pallets/markupsafe/issues/\r\n- Chat: https://discord.gg/pallets\r\n", + "description_content_type": "text/x-rst", + "home_page": "https://palletsprojects.com/p/markupsafe/", + "maintainer": "Pallets", + "maintainer_email": "contact@palletsprojects.com", + "license": "BSD-3-Clause", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + "Topic :: Text Processing :: Markup :: HTML" + ], + "requires_python": ">=3.7", + "project_url": [ + "Donate, https://palletsprojects.com/donate", + "Documentation, https://markupsafe.palletsprojects.com/", + "Changes, https://markupsafe.palletsprojects.com/changes/", + "Source Code, https://github.com/pallets/markupsafe/", + "Issue Tracker, https://github.com/pallets/markupsafe/issues/", + "Chat, https://discord.gg/pallets" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", + "archive_info": { + "hash": "sha256=df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", + "hashes": { + "sha256": "df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "matplotlib-inline", + "version": "0.1.7", + "summary": "Inline Matplotlib backend for Jupyter", + "description": "# Matplotlib Inline Back-end for IPython and Jupyter\n\nThis package provides support for matplotlib to display figures directly inline in the Jupyter notebook and related clients, as shown below.\n\n## Installation\n\nWith conda:\n\n```bash\nconda install -c conda-forge matplotlib-inline\n```\n\nWith pip:\n\n```bash\npip install matplotlib-inline\n```\n\n## Usage\n\nNote that in current versions of JupyterLab and Jupyter Notebook, the explicit use of the `%matplotlib inline` directive is not needed anymore, though other third-party clients may still require it.\n\nThis will produce a figure immediately below:\n\n```python\n%matplotlib inline\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nx = np.linspace(0, 3*np.pi, 500)\nplt.plot(x, np.sin(x**2))\nplt.title('A simple chirp');\n```\n\n## License\n\nLicensed under the terms of the BSD 3-Clause License, by the IPython Development Team (see `LICENSE` file).\n", + "description_content_type": "text/markdown", + "keywords": [ + "ipython", + "jupyter", + "matplotlib", + "python" + ], + "author_email": "IPython Development Team ", + "license": "BSD 3-Clause License\n\nCopyright (c) 2019-2022, IPython Development Team.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Framework :: IPython", + "Framework :: Jupyter", + "Framework :: Jupyter :: JupyterLab", + "Framework :: Jupyter :: JupyterLab :: 3", + "Framework :: Jupyter :: JupyterLab :: 4", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Multimedia :: Graphics" + ], + "requires_dist": [ + "traitlets" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://github.com/ipython/matplotlib-inline" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/b8/bb/bb5b6a515d1584aa2fd89965b11db6632e4bdc69495a52374bcc36e56cfa/nbconvert-7.16.4-py3-none-any.whl", + "archive_info": { + "hash": "sha256=05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3", + "hashes": { + "sha256": "05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "nbconvert", + "version": "7.16.4", + "summary": "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`).", + "description": "# nbconvert\n\n### Jupyter Notebook Conversion\n\n[![Build Status](https://github.com/jupyter/nbconvert/actions/workflows/tests.yml/badge.svg?query=branch%3Amain++)](https://github.com/jupyter/nbconvert/actions/workflows/tests.yml/badge.svg?query=branch%3Amain++)\n[![Documentation Status](https://readthedocs.org/projects/nbconvert/badge/?version=latest)](https://nbconvert.readthedocs.io/en/latest/?badge=latest)\n\nThe **nbconvert** tool, `jupyter nbconvert`, converts notebooks to various other\nformats via [Jinja] templates. The nbconvert tool allows you to convert an\n`.ipynb` notebook file into various static formats including:\n\n- HTML\n- LaTeX\n- PDF\n- Reveal JS\n- Markdown (md)\n- ReStructured Text (rst)\n- executable script\n\n## Usage\n\nFrom the command line, use nbconvert to convert a Jupyter notebook (_input_) to a\na different format (_output_). The basic command structure is:\n\n```\n$ jupyter nbconvert --to \n```\n\nwhere `` is the desired output format and `` is the\nfilename of the Jupyter notebook.\n\n### Example: Convert a notebook to HTML\n\nConvert Jupyter notebook file, `mynotebook.ipynb`, to HTML using:\n\n```\n$ jupyter nbconvert --to html mynotebook.ipynb\n```\n\nThis command creates an HTML output file named `mynotebook.html`.\n\n## Dev Install\n\nCheck if pandoc is installed (`pandoc --version`); if needed, install:\n\n```\nsudo apt-get install pandoc\n```\n\nOr\n\n```\nbrew install pandoc\n```\n\nInstall nbconvert for development using:\n\n```\ngit clone https://github.com/jupyter/nbconvert.git\ncd nbconvert\npip install -e .\n```\n\nRunning the tests after a dev install above:\n\n```\npip install nbconvert[test]\npy.test --pyargs nbconvert\n```\n\n## Documentation\n\n- [Documentation for Jupyter nbconvert](https://nbconvert.readthedocs.io/en/latest/)\n- [nbconvert examples on GitHub](https://github.com/jupyter/nbconvert-examples)\n- [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html)\n\n## Technical Support\n\n- [Issues and Bug Reports](https://github.com/jupyter/nbconvert/issues): A place to report\n bugs or regressions found for nbconvert\n- [Community Technical Support and Discussion - Discourse](https://discourse.jupyter.org/): A place for\n installation, configuration, and troubleshooting assistannce by the Jupyter community.\n As a non-profit project and maintainers who are primarily volunteers, we encourage you\n to ask questions and share your knowledge on Discourse.\n\n## Jupyter Resources\n\n- [Jupyter mailing list](https://groups.google.com/forum/#!forum/jupyter)\n- [Project Jupyter website](https://jupyter.org)\n\n## About the Jupyter Development Team\n\nThe Jupyter Development Team is the set of all contributors to the Jupyter project.\nThis includes all of the Jupyter subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttps://github.com/jupyter/.\n\n## Our Copyright Policy\n\nJupyter uses a shared copyright model. Each contributor maintains copyright\nover their contributions to Jupyter. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the Jupyter\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire Jupyter\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the Jupyter repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n```\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n```\n\n[jinja]: http://jinja.pocoo.org/\n", + "description_content_type": "text/markdown", + "keywords": [ + "Interactive", + "Interpreter", + "Shell", + "Web" + ], + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\n- Copyright (c) 2001-2015, IPython Development Team\n- Copyright (c) 2015-, Jupyter Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3" + ], + "requires_dist": [ + "beautifulsoup4", + "bleach!=5.0.0", + "defusedxml", + "importlib-metadata>=3.6; python_version < '3.10'", + "jinja2>=3.0", + "jupyter-core>=4.7", + "jupyterlab-pygments", + "markupsafe>=2.0", + "mistune<4,>=2.0.3", + "nbclient>=0.5.0", + "nbformat>=5.7", + "packaging", + "pandocfilters>=1.4.1", + "pygments>=2.4.1", + "tinycss2", + "traitlets>=5.1", + "flaky; extra == 'all'", + "ipykernel; extra == 'all'", + "ipython; extra == 'all'", + "ipywidgets>=7.5; extra == 'all'", + "myst-parser; extra == 'all'", + "nbsphinx>=0.2.12; extra == 'all'", + "playwright; extra == 'all'", + "pydata-sphinx-theme; extra == 'all'", + "pyqtwebengine>=5.15; extra == 'all'", + "pytest>=7; extra == 'all'", + "sphinx==5.0.2; extra == 'all'", + "sphinxcontrib-spelling; extra == 'all'", + "tornado>=6.1; extra == 'all'", + "ipykernel; extra == 'docs'", + "ipython; extra == 'docs'", + "myst-parser; extra == 'docs'", + "nbsphinx>=0.2.12; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinx==5.0.2; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "pyqtwebengine>=5.15; extra == 'qtpdf'", + "pyqtwebengine>=5.15; extra == 'qtpng'", + "tornado>=6.1; extra == 'serve'", + "flaky; extra == 'test'", + "ipykernel; extra == 'test'", + "ipywidgets>=7.5; extra == 'test'", + "pytest>=7; extra == 'test'", + "playwright; extra == 'webpdf'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://jupyter.org" + ], + "provides_extra": [ + "all", + "docs", + "qtpdf", + "qtpng", + "serve", + "test", + "webpdf" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", + "archive_info": { + "hash": "sha256=3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", + "hashes": { + "sha256": "3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "nbformat", + "version": "5.10.4", + "summary": "The Jupyter Notebook format", + "description": "This package contains the base implementation of the Jupyter Notebook format,\nand Python APIs for working with notebooks.", + "description_content_type": "text/plain", + "keywords": [ + "Interactive", + "Interpreter", + "Shell", + "Web" + ], + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\n- Copyright (c) 2001-2015, IPython Development Team\n- Copyright (c) 2015-, Jupyter Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" + ], + "requires_dist": [ + "fastjsonschema>=2.15", + "jsonschema>=2.6", + "jupyter-core!=5.0.*,>=4.12", + "traitlets>=5.1", + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinx; extra == 'docs'", + "sphinxcontrib-github-alt; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "pep440; extra == 'test'", + "pre-commit; extra == 'test'", + "pytest; extra == 'test'", + "testpath; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://jupyter.org", + "Changelog, https://github.com/jupyter/nbformat/blob/main/CHANGELOG.md", + "Documentation, https://nbformat.readthedocs.io/", + "Repository, https://github.com/jupyter/nbformat.git" + ], + "provides_extra": [ + "docs", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", + "hashes": { + "sha256": "c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "overrides", + "version": "7.7.0", + "summary": "A decorator to automatically detect mismatch when overriding a method.", + "description": "overrides\n=========\n\n.. image:: https://img.shields.io/pypi/v/overrides.svg\n :target: https://pypi.python.org/pypi/overrides\n\n.. image:: http://pepy.tech/badge/overrides\n :target: http://pepy.tech/project/overrides\n\nA decorator ``@override`` that verifies that a method that should override an inherited method actually does it.\n\nCopies the docstring of the inherited method to the overridden method.\n\nSince signature validation and docstring inheritance are performed on class creation and not on class instantiation,\nthis library significantly improves the safety and experience of creating class hierarchies in \nPython without significantly impacting performance. See https://stackoverflow.com/q/1167617 for the\ninitial inspiration for this library.\n\nMotivation\n----------\n\nPython has no standard mechanism by which to guarantee that (1) a method that previously overrode an inherited method\ncontinues to do so, and (2) a method that previously did not override an inherited will not override now.\nThis opens the door for subtle problems as class hierarchies evolve over time. For example,\n\n1. A method that is added to a superclass is shadowed by an existing method with the same name in a \n subclass.\n\n2. A method of a superclass that is overridden by a subclass is renamed in the superclass but not in \n the subclass.\n\n3. A method of a superclass that is overridden by a subclass is removed in the superclass but not in\n the subclass.\n\n4. A method of a superclass that is overridden by a subclass but the signature of the overridden\n method is incompatible with that of the inherited one.\n\nThese can be only checked by explicitly marking method override in the code.\n\nPython also has no standard mechanism by which to inherit docstrings in overridden methods. Because \nmost standard linters (e.g., flake8) have rules that require all public methods to have a docstring, \nthis inevitably leads to a proliferation of ``See parent class for usage`` docstrings on overridden\nmethods, or, worse, to a disabling of these rules altogether. In addition, mediocre or missing\ndocstrings degrade the quality of tooltips and completions that can be provided by an editor.\n\nInstallation\n------------\n\nCompatible with Python 3.6+.\n\n.. code-block:: bash\n\n $ pip install overrides\n\nUsage\n-----\n\nUse ``@override`` to indicate that a subclass method should override a superclass method.\n\n.. code-block:: python\n\n from overrides import override\n\n class SuperClass:\n\n def foo(self):\n \"\"\"This docstring will be inherited by any method that overrides this!\"\"\"\n return 1\n\n def bar(self, x) -> str:\n return x\n\n class SubClass(SuperClass):\n\n @override\n def foo(self):\n return 2\n\n @override\n def bar(self, y) -> int: # Raises, because the signature is not compatible.\n return y\n \n @override\n def zoo(self): # Raises, because does not exist in the super class.\n return \"foobarzoo\"\n\nUse ``EnforceOverrides`` to require subclass methods that shadow superclass methods to be decorated \nwith ``@override``.\n\n.. code-block:: python\n \n from overrides import EnforceOverrides\n\n class SuperClass(EnforceOverrides):\n\n def foo(self):\n return 1\n\n class SubClass(SuperClass):\n\n def foo(self): # Raises, because @override is missing.\n return 2\n\nUse ``@final`` to indicate that a superclass method cannot be overriden.\nWith Python 3.11 and above ``@final`` is directly `typing.final `_.\n\n.. code-block:: python\n\n from overrides import EnforceOverrides, final, override\n\n class SuperClass(EnforceOverrides):\n\n @final\n def foo(self):\n return 1\n\n class SubClass(SuperClass):\n\n @override\n def foo(self): # Raises, because overriding a final method is forbidden.\n return 2\n\nNote that ``@classmethod`` and ``@staticmethod`` must be declared before ``@override``.\n\n.. code-block:: python\n\n from overrides import override\n\n class SuperClass:\n\n @staticmethod\n def foo(x):\n return 1\n\n class SubClass(SuperClass):\n\n @staticmethod\n @override\n def foo(x):\n return 2\n\n\nFlags of control\n----------------\n\n.. code-block:: python\n\n # To prevent all signature checks do:\n @override(check_signature=False)\n def some_method(self, now_this_can_be_funny_and_wrong: str, what_ever: int) -> \"Dictirux\":\n pass\n\n # To do the check only at runtime and solve some forward reference problems\n @override(check_at_runtime=True)\n def some_other_method(self, ..) -> \"SomethingDefinedLater\":\n pass\n\n a.some_other_method() # Kaboom if not SomethingDefinedLater\n\n\nContributors\n------------\n\nThis project exists only through the work of all the people who contribute.\n\nmkorpela, drorasaf, ngoodman90, TylerYep, leeopop, donpatrice, jayvdb, joelgrus, lisyarus, \nsoulmerge, rkr-at-dbx, ashwin153, brentyi, jobh, tjsmart, bersbersbers, LysanderGG, mgorny.\n", + "keywords": [ + "override", + "inheritence", + "OOP" + ], + "home_page": "https://github.com/mkorpela/overrides", + "author": "Mikko Korpela", + "author_email": "mikko.korpela@gmail.com", + "license": "Apache License, Version 2.0", + "classifier": [ + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9" + ], + "requires_dist": [ + "typing ; python_version < \"3.5\"" + ], + "requires_python": ">=3.6" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/68/13/2aa1f0e1364feb2c9ef45302f387ac0bd81484e9c9a4c5688a322fbdfd08/platformdirs-4.2.2-py3-none-any.whl", + "archive_info": { + "hash": "sha256=2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "hashes": { + "sha256": "2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "platformdirs", + "version": "4.2.2", + "summary": "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`.", + "description": "The problem\n===========\n\n.. image:: https://github.com/platformdirs/platformdirs/actions/workflows/check.yml/badge.svg\n :target: https://github.com/platformdirs/platformdirs/actions\n\nWhen writing desktop application, finding the right location to store user data\nand configuration varies per platform. Even for single-platform apps, there\nmay by plenty of nuances in figuring out the right location.\n\nFor example, if running on macOS, you should use::\n\n ~/Library/Application Support/\n\nIf on Windows (at least English Win) that should be::\n\n C:\\Documents and Settings\\\\Application Data\\Local Settings\\\\\n\nor possibly::\n\n C:\\Documents and Settings\\\\Application Data\\\\\n\nfor `roaming profiles `_ but that is another story.\n\nOn Linux (and other Unices), according to the `XDG Basedir Spec`_, it should be::\n\n ~/.local/share/\n\n.. _XDG Basedir Spec: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html\n\n``platformdirs`` to the rescue\n==============================\n\nThis kind of thing is what the ``platformdirs`` package is for.\n``platformdirs`` will help you choose an appropriate:\n\n- user data dir (``user_data_dir``)\n- user config dir (``user_config_dir``)\n- user cache dir (``user_cache_dir``)\n- site data dir (``site_data_dir``)\n- site config dir (``site_config_dir``)\n- user log dir (``user_log_dir``)\n- user documents dir (``user_documents_dir``)\n- user downloads dir (``user_downloads_dir``)\n- user pictures dir (``user_pictures_dir``)\n- user videos dir (``user_videos_dir``)\n- user music dir (``user_music_dir``)\n- user desktop dir (``user_desktop_dir``)\n- user runtime dir (``user_runtime_dir``)\n\nAnd also:\n\n- Is slightly opinionated on the directory names used. Look for \"OPINION\" in\n documentation and code for when an opinion is being applied.\n\nExample output\n==============\n\nOn macOS:\n\n.. code-block:: pycon\n\n >>> from platformdirs import *\n >>> appname = \"SuperApp\"\n >>> appauthor = \"Acme\"\n >>> user_data_dir(appname, appauthor)\n '/Users/trentm/Library/Application Support/SuperApp'\n >>> site_data_dir(appname, appauthor)\n '/Library/Application Support/SuperApp'\n >>> user_cache_dir(appname, appauthor)\n '/Users/trentm/Library/Caches/SuperApp'\n >>> user_log_dir(appname, appauthor)\n '/Users/trentm/Library/Logs/SuperApp'\n >>> user_documents_dir()\n '/Users/trentm/Documents'\n >>> user_downloads_dir()\n '/Users/trentm/Downloads'\n >>> user_pictures_dir()\n '/Users/trentm/Pictures'\n >>> user_videos_dir()\n '/Users/trentm/Movies'\n >>> user_music_dir()\n '/Users/trentm/Music'\n >>> user_desktop_dir()\n '/Users/trentm/Desktop'\n >>> user_runtime_dir(appname, appauthor)\n '/Users/trentm/Library/Caches/TemporaryItems/SuperApp'\n\nOn Windows:\n\n.. code-block:: pycon\n\n >>> from platformdirs import *\n >>> appname = \"SuperApp\"\n >>> appauthor = \"Acme\"\n >>> user_data_dir(appname, appauthor)\n 'C:\\\\Users\\\\trentm\\\\AppData\\\\Local\\\\Acme\\\\SuperApp'\n >>> user_data_dir(appname, appauthor, roaming=True)\n 'C:\\\\Users\\\\trentm\\\\AppData\\\\Roaming\\\\Acme\\\\SuperApp'\n >>> user_cache_dir(appname, appauthor)\n 'C:\\\\Users\\\\trentm\\\\AppData\\\\Local\\\\Acme\\\\SuperApp\\\\Cache'\n >>> user_log_dir(appname, appauthor)\n 'C:\\\\Users\\\\trentm\\\\AppData\\\\Local\\\\Acme\\\\SuperApp\\\\Logs'\n >>> user_documents_dir()\n 'C:\\\\Users\\\\trentm\\\\Documents'\n >>> user_downloads_dir()\n 'C:\\\\Users\\\\trentm\\\\Downloads'\n >>> user_pictures_dir()\n 'C:\\\\Users\\\\trentm\\\\Pictures'\n >>> user_videos_dir()\n 'C:\\\\Users\\\\trentm\\\\Videos'\n >>> user_music_dir()\n 'C:\\\\Users\\\\trentm\\\\Music'\n >>> user_desktop_dir()\n 'C:\\\\Users\\\\trentm\\\\Desktop'\n >>> user_runtime_dir(appname, appauthor)\n 'C:\\\\Users\\\\trentm\\\\AppData\\\\Local\\\\Temp\\\\Acme\\\\SuperApp'\n\nOn Linux:\n\n.. code-block:: pycon\n\n >>> from platformdirs import *\n >>> appname = \"SuperApp\"\n >>> appauthor = \"Acme\"\n >>> user_data_dir(appname, appauthor)\n '/home/trentm/.local/share/SuperApp'\n >>> site_data_dir(appname, appauthor)\n '/usr/local/share/SuperApp'\n >>> site_data_dir(appname, appauthor, multipath=True)\n '/usr/local/share/SuperApp:/usr/share/SuperApp'\n >>> user_cache_dir(appname, appauthor)\n '/home/trentm/.cache/SuperApp'\n >>> user_log_dir(appname, appauthor)\n '/home/trentm/.local/state/SuperApp/log'\n >>> user_config_dir(appname)\n '/home/trentm/.config/SuperApp'\n >>> user_documents_dir()\n '/home/trentm/Documents'\n >>> user_downloads_dir()\n '/home/trentm/Downloads'\n >>> user_pictures_dir()\n '/home/trentm/Pictures'\n >>> user_videos_dir()\n '/home/trentm/Videos'\n >>> user_music_dir()\n '/home/trentm/Music'\n >>> user_desktop_dir()\n '/home/trentm/Desktop'\n >>> user_runtime_dir(appname, appauthor)\n '/run/user/{os.getuid()}/SuperApp'\n >>> site_config_dir(appname)\n '/etc/xdg/SuperApp'\n >>> os.environ[\"XDG_CONFIG_DIRS\"] = \"/etc:/usr/local/etc\"\n >>> site_config_dir(appname, multipath=True)\n '/etc/SuperApp:/usr/local/etc/SuperApp'\n\nOn Android::\n\n >>> from platformdirs import *\n >>> appname = \"SuperApp\"\n >>> appauthor = \"Acme\"\n >>> user_data_dir(appname, appauthor)\n '/data/data/com.myApp/files/SuperApp'\n >>> user_cache_dir(appname, appauthor)\n '/data/data/com.myApp/cache/SuperApp'\n >>> user_log_dir(appname, appauthor)\n '/data/data/com.myApp/cache/SuperApp/log'\n >>> user_config_dir(appname)\n '/data/data/com.myApp/shared_prefs/SuperApp'\n >>> user_documents_dir()\n '/storage/emulated/0/Documents'\n >>> user_downloads_dir()\n '/storage/emulated/0/Downloads'\n >>> user_pictures_dir()\n '/storage/emulated/0/Pictures'\n >>> user_videos_dir()\n '/storage/emulated/0/DCIM/Camera'\n >>> user_music_dir()\n '/storage/emulated/0/Music'\n >>> user_desktop_dir()\n '/storage/emulated/0/Desktop'\n >>> user_runtime_dir(appname, appauthor)\n '/data/data/com.myApp/cache/SuperApp/tmp'\n\nNote: Some android apps like Termux and Pydroid are used as shells. These\napps are used by the end user to emulate Linux environment. Presence of\n``SHELL`` environment variable is used by Platformdirs to differentiate\nbetween general android apps and android apps used as shells. Shell android\napps also support ``XDG_*`` environment variables.\n\n\n``PlatformDirs`` for convenience\n================================\n\n.. code-block:: pycon\n\n >>> from platformdirs import PlatformDirs\n >>> dirs = PlatformDirs(\"SuperApp\", \"Acme\")\n >>> dirs.user_data_dir\n '/Users/trentm/Library/Application Support/SuperApp'\n >>> dirs.site_data_dir\n '/Library/Application Support/SuperApp'\n >>> dirs.user_cache_dir\n '/Users/trentm/Library/Caches/SuperApp'\n >>> dirs.user_log_dir\n '/Users/trentm/Library/Logs/SuperApp'\n >>> dirs.user_documents_dir\n '/Users/trentm/Documents'\n >>> dirs.user_downloads_dir\n '/Users/trentm/Downloads'\n >>> dirs.user_pictures_dir\n '/Users/trentm/Pictures'\n >>> dirs.user_videos_dir\n '/Users/trentm/Movies'\n >>> dirs.user_music_dir\n '/Users/trentm/Music'\n >>> dirs.user_desktop_dir\n '/Users/trentm/Desktop'\n >>> dirs.user_runtime_dir\n '/Users/trentm/Library/Caches/TemporaryItems/SuperApp'\n\nPer-version isolation\n=====================\n\nIf you have multiple versions of your app in use that you want to be\nable to run side-by-side, then you may want version-isolation for these\ndirs::\n\n >>> from platformdirs import PlatformDirs\n >>> dirs = PlatformDirs(\"SuperApp\", \"Acme\", version=\"1.0\")\n >>> dirs.user_data_dir\n '/Users/trentm/Library/Application Support/SuperApp/1.0'\n >>> dirs.site_data_dir\n '/Library/Application Support/SuperApp/1.0'\n >>> dirs.user_cache_dir\n '/Users/trentm/Library/Caches/SuperApp/1.0'\n >>> dirs.user_log_dir\n '/Users/trentm/Library/Logs/SuperApp/1.0'\n >>> dirs.user_documents_dir\n '/Users/trentm/Documents'\n >>> dirs.user_downloads_dir\n '/Users/trentm/Downloads'\n >>> dirs.user_pictures_dir\n '/Users/trentm/Pictures'\n >>> dirs.user_videos_dir\n '/Users/trentm/Movies'\n >>> dirs.user_music_dir\n '/Users/trentm/Music'\n >>> dirs.user_desktop_dir\n '/Users/trentm/Desktop'\n >>> dirs.user_runtime_dir\n '/Users/trentm/Library/Caches/TemporaryItems/SuperApp/1.0'\n\nBe wary of using this for configuration files though; you'll need to handle\nmigrating configuration files manually.\n\nWhy this Fork?\n==============\n\nThis repository is a friendly fork of the wonderful work started by\n`ActiveState `_ who created\n``appdirs``, this package's ancestor.\n\nMaintaining an open source project is no easy task, particularly\nfrom within an organization, and the Python community is indebted\nto ``appdirs`` (and to Trent Mick and Jeff Rouse in particular) for\ncreating an incredibly useful simple module, as evidenced by the wide\nnumber of users it has attracted over the years.\n\nNonetheless, given the number of long-standing open issues\nand pull requests, and no clear path towards `ensuring\nthat maintenance of the package would continue or grow\n`_, this fork was\ncreated.\n\nContributions are most welcome.\n", + "description_content_type": "text/x-rst", + "keywords": [ + "appdirs", + "application", + "cache", + "directory", + "log", + "user" + ], + "maintainer_email": "Bernát Gábor , Julian Berman , Ofek Lev , Ronny Pfannschmidt ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development :: Libraries :: Python Modules" + ], + "requires_dist": [ + "furo>=2023.9.10; extra == 'docs'", + "proselint>=0.13; extra == 'docs'", + "sphinx-autodoc-typehints>=1.25.2; extra == 'docs'", + "sphinx>=7.2.6; extra == 'docs'", + "appdirs==1.4.4; extra == 'test'", + "covdefaults>=2.3; extra == 'test'", + "pytest-cov>=4.1; extra == 'test'", + "pytest-mock>=3.12; extra == 'test'", + "pytest>=7.4.3; extra == 'test'", + "mypy>=1.8; extra == 'type'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://platformdirs.readthedocs.io", + "Homepage, https://github.com/platformdirs/platformdirs", + "Source, https://github.com/platformdirs/platformdirs", + "Tracker, https://github.com/platformdirs/platformdirs/issues" + ], + "provides_extra": [ + "docs", + "test", + "type" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/c7/98/745b810d822103adca2df8decd4c0bbe839ba7ad3511af3f0d09692fc0f0/prometheus_client-0.20.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7", + "hashes": { + "sha256": "cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "prometheus_client", + "version": "0.20.0", + "summary": "Python client for the Prometheus monitoring system.", + "description": "# Prometheus Python Client\n\nThe official Python client for [Prometheus](https://prometheus.io).\n\n## Installation\n\n```\npip install prometheus-client\n```\n\nThis package can be found on [PyPI](https://pypi.python.org/pypi/prometheus_client).\n\n## Documentation\n\nDocumentation is available on https://prometheus.github.io/client_python\n\n## Links\n\n* [Releases](https://github.com/prometheus/client_python/releases): The releases page shows the history of the project and acts as a changelog.\n* [PyPI](https://pypi.python.org/pypi/prometheus_client)\n", + "description_content_type": "text/markdown", + "keywords": [ + "prometheus", + "monitoring", + "instrumentation", + "client" + ], + "home_page": "https://github.com/prometheus/client_python", + "author": "Brian Brazil", + "author_email": "brian.brazil@robustperception.io", + "license": "Apache Software License 2.0", + "classifier": [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "Intended Audience :: System Administrators", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: System :: Monitoring", + "License :: OSI Approved :: Apache Software License" + ], + "requires_dist": [ + "twisted ; extra == 'twisted'" + ], + "requires_python": ">=3.8", + "provides_extra": [ + "twisted" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", + "archive_info": { + "hash": "sha256=37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", + "hashes": { + "sha256": "37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "pywin32", + "version": "306", + "summary": "Python for Window Extensions", + "description": "# pywin32\r\n\r\n[![CI](https://github.com/mhammond/pywin32/workflows/CI/badge.svg)](https://github.com/mhammond/pywin32/actions?query=workflow%3ACI)\r\n[![PyPI - Version](https://img.shields.io/pypi/v/pywin32.svg)](https://pypi.org/project/pywin32)\r\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pywin32.svg)](https://pypi.org/project/pywin32)\r\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/pywin32.svg)](https://pypi.org/project/pywin32)\r\n[![License - PSF-2.0](https://img.shields.io/badge/license-PSF--2.0-9400d3.svg)](https://spdx.org/licenses/PSF-2.0.html)\r\n\r\n-----\r\n\r\nThis is the readme for the Python for Win32 (pywin32) extensions, which provides access to many of the Windows APIs from Python.\r\n\r\nSee [CHANGES.txt](https://github.com/mhammond/pywin32/blob/master/CHANGES.txt) for recent notable changes.\r\n\r\nOnly Python 3 is supported. If you want Python 2 support, you want build `228`.\r\n\r\n## Docs\r\n\r\nThe docs are a long and sad story, but [there's now an online version](https://mhammond.github.io/pywin32/)\r\nof the helpfile that ships with the installers (thanks [@ofek](https://github.com/mhammond/pywin32/pull/1774)!).\r\nLots of that is very old, but some is auto-generated and current. Would love help untangling the docs!\r\n\r\n## Support\r\n\r\nFeel free to [open issues](https://github.com/mhammond/pywin32/issues) for\r\nall bugs (or suspected bugs) in pywin32. [pull-requests](https://github.com/mhammond/pywin32/pulls)\r\nfor all bugs or features are also welcome.\r\n\r\nHowever, please **do not open github issues for general support requests**, or\r\nfor problems or questions using the modules in this package - they will be\r\nclosed. For such issues, please email the\r\n[python-win32 mailing list](http://mail.python.org/mailman/listinfo/python-win32) -\r\nnote that you must be subscribed to the list before posting.\r\n\r\n## Binaries\r\n[Binary releases are deprecated.](https://mhammond.github.io/pywin32_installers.html)\r\nWhile they are still provided, [find them here](https://github.com/mhammond/pywin32/releases)\r\n\r\n## Installing via PIP\r\n\r\nYou should install pywin32 via pip - eg,\r\n> python -m pip install --upgrade pywin32\r\n\r\nIf you encounter any problems when upgrading (eg, \"module not found\" errors or similar), you\r\nshould execute:\r\n\r\n> python Scripts/pywin32_postinstall.py -install\r\n\r\nThis will make some small attempts to cleanup older conflicting installs.\r\n\r\nNote that if you want to use pywin32 for \"system wide\" features, such as\r\nregistering COM objects or implementing Windows Services, then you must run\r\nthat command from an elevated (ie, \"Run as Administrator) command prompt.\r\n\r\nFor unreleased changes, you can download builds made by [github actions](https://github.com/mhammond/pywin32/actions/) -\r\nchoose any \"workflow\" from the `main` branch and download its \"artifacts\")\r\n\r\n### `The specified procedure could not be found` / `Entry-point not found` Errors?\r\nA very common report is that people install pywin32, but many imports fail with errors\r\nsimilar to the above.\r\n\r\nIn almost all cases, this tends to mean there are other pywin32 DLLs installed in your system,\r\nbut in a different location than the new ones. This sometimes happens in environments that\r\ncome with pywin32 pre-shipped (eg, anaconda?).\r\n\r\nThe possible solutions are:\r\n\r\n* Run the \"post_install\" script documented above.\r\n\r\n* Otherwise, find and remove all other copies of `pywintypesXX.dll` and `pythoncomXX.dll`\r\n (where `XX` is the Python version - eg, \"39\")\r\n\r\n### Running as a Windows Service\r\n\r\nModern Python installers do not, by default, install Python in a way that is suitable for\r\nrunning as a service, particularly for other users.\r\n\r\n* Ensure Python is installed in a location where the user running the service has\r\n access to the installation and is able to load `pywintypesXX.dll` and `pythonXX.dll`.\r\n\r\n* Manually copy `pythonservice.exe` from the `site-packages/win32` directory to\r\n the same place as these DLLs.\r\n\r\n## Building from source\r\n\r\nInstall Visual Studio 2019 (later probably works, but options might be different),\r\nselect \"Desktop Development with C++\", then the following options:\r\n* Windows 10 SDK (latest offered I guess? At time of writing, 10.0.18362)\r\n* \"C++ for MFC for ...\"\r\n* ARM build tools if necessary.\r\n\r\n(the free compilers probably work too, but haven't been tested - let me know your experiences!)\r\n\r\n`setup.py` is a standard distutils build script, so you probably want:\r\n\r\n> python setup.py install\r\n\r\nor\r\n\r\n> python setup.py --help\r\n\r\nSome modules need obscure SDKs to build - `setup.py` should succeed, gracefully\r\ntelling you why it failed to build them - if the build actually fails with your\r\nconfiguration, please [open an issue](https://github.com/mhammond/pywin32/issues).\r\n\r\n## Release process\r\n\r\nThe following steps are performed when making a new release - this is mainly\r\nto form a checklist so mhammond doesn't forget what to do :)\r\n\r\n* Ensure CHANGES.txt has everything worth noting, commit it.\r\n\r\n* Update setup.py with the new build number.\r\n\r\n* Execute build.bat, wait forever, test the artifacts.\r\n\r\n* Upload .whl artifacts to pypi - we do this before pushing the tag because they might be\r\n rejected for an invalid `README.md`. Done via `py -3.? -m twine upload dist/*XXX*.whl`.\r\n\r\n* Commit setup.py (so the new build number is in the repo), create a new git tag\r\n\r\n* Upload the .exe installers to github.\r\n\r\n* Update setup.py with the new build number + \".1\" (eg, 123.1), to ensure\r\n future test builds aren't mistaken for the real release.\r\n\r\n* Make sure everything is pushed to github, including the tag (ie,\r\n `git push --tags`)\r\n\r\n* Send mail to python-win32\r\n", + "description_content_type": "text/markdown", + "home_page": "https://github.com/mhammond/pywin32", + "author": "Mark Hammond (et al)", + "author_email": "mhammond@skippinet.com.au", + "license": "PSF", + "classifier": [ + "Environment :: Win32 (MS Windows)", + "Intended Audience :: Developers", + "License :: OSI Approved :: Python Software Foundation License", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/49/37/c0dcb1dca094af3605dd22c0528839a65bc4e1e78bb91eb12841d18fa3f1/pywinpty-2.0.13-cp312-none-win_amd64.whl", + "archive_info": { + "hash": "sha256=2fd876b82ca750bb1333236ce98488c1be96b08f4f7647cfdf4129dfad83c2d4", + "hashes": { + "sha256": "2fd876b82ca750bb1333236ce98488c1be96b08f4f7647cfdf4129dfad83c2d4" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "pywinpty", + "version": "2.0.13", + "summary": "Pseudo terminal support for Windows from Python.", + "description": "# PyWinpty: Pseudoterminals for Windows in Python\r\n\r\n[![Project License - MIT](https://img.shields.io/pypi/l/pywinpty.svg)](./LICENSE.txt)\r\n[![pypi version](https://img.shields.io/pypi/v/pywinpty.svg)](https://pypi.org/project/pywinpty/)\r\n[![conda version](https://img.shields.io/conda/vn/conda-forge/pywinpty.svg)](https://www.anaconda.com/download/)\r\n[![download count](https://img.shields.io/conda/dn/conda-forge/pywinpty.svg)](https://www.anaconda.com/download/)\r\n[![Downloads](https://pepy.tech/badge/pywinpty)](https://pepy.tech/project/pywinpty)\r\n[![PyPI status](https://img.shields.io/pypi/status/pywinpty.svg)](https://github.com/spyder-ide/pywinpty)\r\n[![Windows tests](https://github.com/andfoy/pywinpty/actions/workflows/windows_build.yml/badge.svg)](https://github.com/andfoy/pywinpty/actions/workflows/windows_build.yml)\r\n\r\n*Copyright © 2017–2022 Spyder Project Contributors*\r\n*Copyright © 2022– Edgar Andrés Margffoy Tuay*\r\n\r\n\r\n## Overview\r\n\r\nPyWinpty allows creating and communicating with Windows processes that receive input and print outputs via console input and output pipes. PyWinpty supports both the native [ConPTY](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/) interface and the previous, fallback [winpty](https://github.com/rprichard/winpty) library.\r\n\r\n\r\n## Dependencies\r\nTo compile pywinpty sources, you must have [Rust](https://rustup.rs/) installed.\r\nOptionally, you can also have Winpty's C header and library files available on your include path.\r\n\r\n\r\n## Installation\r\nYou can install this library by using conda or pip package managers, as it follows:\r\n\r\nUsing conda (Recommended):\r\n```bash\r\nconda install pywinpty\r\n```\r\n\r\nUsing pip:\r\n```bash\r\npip install pywinpty\r\n```\r\n\r\n## Building from source\r\n\r\nTo build from sources, you will require both a working stable or nightly Rust toolchain with\r\ntarget `x86_64-pc-windows-msvc`, which can be installed using [rustup](https://rustup.rs/).\r\n\r\nOptionally, this library can be linked against winpty library, which you can install using conda-forge:\r\n\r\n```batch\r\nconda install winpty -c conda-forge\r\n```\r\n\r\nIf you don't want to use conda, you will need to have the winpty binaries and headers available on your PATH.\r\n\r\nFinally, pywinpty uses [Maturin](https://github.com/PyO3/maturin) as the build backend, which can be installed using `pip`:\r\n\r\n```batch\r\npip install maturin\r\n```\r\n\r\nTo test your compilation environment settings, you can build pywinpty sources locally, by\r\nexecuting:\r\n\r\n```bash\r\nmaturin develop\r\n```\r\n\r\nThis package depends on the following Rust crates:\r\n\r\n* [PyO3](https://github.com/PyO3/pyo3): Library used to produce Python bindings from Rust code.\r\n* [WinPTY-rs](https://github.com/andfoy/winpty-rs): Create and spawn processes inside a pseudoterminal in Windows from Rust.\r\n* [Maturin](https://github.com/PyO3/maturin): Build system to build and publish Rust-based Python packages.\r\n\r\n## Package usage\r\nPywinpty offers a single python wrapper around winpty library functions.\r\nThis implies that using a single object (``winpty.PTY``) it is possible to access to all functionality, as it follows:\r\n\r\n```python\r\n# High level usage using `spawn`\r\nfrom winpty import PtyProcess\r\n\r\nproc = PtyProcess.spawn('python')\r\nproc.write('print(\"hello, world!\")\\r\\n')\r\nproc.write('exit()\\r\\n')\r\nwhile proc.isalive():\r\n\tprint(proc.readline())\r\n\r\n# Low level usage using the raw `PTY` object\r\nfrom winpty import PTY\r\n\r\n# Start a new winpty-agent process of size (cols, rows)\r\ncols, rows = 80, 25\r\nprocess = PTY(cols, rows)\r\n\r\n# Spawn a new console process, e.g., CMD\r\nprocess.spawn(br'C:\\windows\\system32\\cmd.exe')\r\n\r\n# Read console output (Unicode)\r\nprocess.read()\r\n\r\n# Write input to console (Unicode)\r\nprocess.write(b'Text')\r\n\r\n# Resize console size\r\nnew_cols, new_rows = 90, 30\r\nprocess.set_size(new_cols, new_rows)\r\n\r\n# Know if the process is alive\r\nalive = process.isalive()\r\n\r\n# End winpty-agent process\r\ndel process\r\n```\r\n\r\n## Running tests\r\nWe use pytest to run tests as it follows (after calling ``maturin develop``), the test suite depends\r\non pytest-lazy-fixture, which can be installed via pip:\r\n\r\n```batch\r\npip install pytest pytest-lazy-fixture flaky\r\n```\r\n\r\nAll the tests can be exceuted using the following command\r\n\r\n```bash\r\npython runtests.py\r\n```\r\n\r\n\r\n## Changelog\r\nVisit our [CHANGELOG](CHANGELOG.md) file to learn more about our new features and improvements.\r\n\r\n\r\n## Contribution guidelines\r\nWe follow PEP8 and PEP257 for pure python packages and Rust to compile extensions. We use MyPy type annotations for all functions and classes declared on this package. Feel free to send a PR or create an issue if you have any problem/question.\r\n\n", + "description_content_type": "text/markdown; charset=UTF-8; variant=GFM", + "keywords": [ + "pty", + "pseudo-terminal", + "conpty", + "windows", + "winpty" + ], + "author": "Edgar Andrés Margffoy Tuay ", + "author_email": "Edgar Andrés Margffoy Tuay ", + "license": "MIT", + "requires_python": ">=3.8", + "project_url": [ + "Source Code, https://github.com/spyder-ide/pywinpty" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/6c/45/905ec497208808aa0ba2470b2ab36d779b53f4016617feca93baffb6ba7f/pyzmq-26.0.3-cp312-cp312-win_amd64.whl", + "archive_info": { + "hash": "sha256=926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf", + "hashes": { + "sha256": "926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "pyzmq", + "version": "26.0.3", + "summary": "Python bindings for 0MQ", + "description": "# PyZMQ: Python bindings for ØMQ\n\nThis package contains Python bindings for [ZeroMQ](https://zeromq.org).\nØMQ is a lightweight and fast messaging implementation.\n\nPyZMQ should work with any reasonable version of Python (≥ 3.7), as well as PyPy.\nThe Cython backend used by CPython supports libzmq ≥ 2.1.4 (including 3.2.x and 4.x),\nbut the CFFI backend used by PyPy only supports libzmq ≥ 3.2.2 (including 4.x).\n\nFor a summary of changes to pyzmq, see our\n[changelog](https://pyzmq.readthedocs.io/en/latest/changelog.html).\n\n### ØMQ 3.x, 4.x\n\nPyZMQ fully supports the 3.x and 4.x APIs of libzmq,\ndeveloped at [zeromq/libzmq](https://github.com/zeromq/libzmq).\nNo code to change, no flags to pass,\njust build pyzmq against the latest and it should work.\n\nPyZMQ does not support the old libzmq 2 API on PyPy.\n\n## Documentation\n\nSee PyZMQ's Sphinx-generated\ndocumentation [on Read the Docs](https://pyzmq.readthedocs.io) for API\ndetails, and some notes on Python and Cython development. If you want to\nlearn about using ØMQ in general, the excellent [ØMQ\nGuide](http://zguide.zeromq.org/py:all) is the place to start, which has a\nPython version of every example. We also have some information on our\n[wiki](https://github.com/zeromq/pyzmq/wiki).\n\n## Downloading\n\nUnless you specifically want to develop PyZMQ, we recommend downloading\nthe PyZMQ source code or wheels from\n[PyPI](https://pypi.io/project/pyzmq/),\nor install with conda.\n\nYou can also get the latest source code from our GitHub repository, but\nbuilding from the repository will require that you install recent Cython.\n\n## Building and installation\n\nFor more detail on building pyzmq, see [our docs](https://pyzmq.readthedocs.io/en/latest/howto/build.html).\n\nWe build wheels for macOS, Windows, and Linux, so you can get a binary on those platforms with:\n\n```\npip install pyzmq\n```\n\nbut compiling from source with `pip install pyzmq` should work in most environments.\nMake sure you are using the latest pip, or it may not find the right wheels.\n\nIf the wheel doesn't work for some reason, or you want to force pyzmq to be compiled\n(this is often preferable if you already have libzmq installed and configured the way you want it),\nyou can force installation from source with:\n\n```\npip install --no-binary=pyzmq pyzmq\n```\n\n## Old versions\n\npyzmq 16 drops support Python 2.6 and 3.2.\nIf you need to use one of those Python versions, you can pin your pyzmq version to before 16:\n\n```\npip install 'pyzmq<16'\n```\n\nFor libzmq 2.0.x, use 'pyzmq\\<2.1'\n\npyzmq-2.1.11 was the last version of pyzmq to support Python 2.5,\nand pyzmq ≥ 2.2.0 requires Python ≥ 2.6.\npyzmq-13.0.0 introduces PyPy support via CFFI, which only supports libzmq-3.2.2 and newer.\n\nPyZMQ releases ≤ 2.2.0 matched libzmq versioning, but this is no longer the case,\nstarting with PyZMQ 13.0.0 (it was the thirteenth release, so why not?).\nPyZMQ ≥ 13.0 follows semantic versioning conventions accounting only for PyZMQ itself.\n", + "description_content_type": "text/markdown", + "author": "Brian E. Granger, Min Ragan-Kelley", + "author_email": "PyZMQ Contributors ", + "license": "BSD 3-Clause License\n\nCopyright (c) 2009-2012, Brian Granger, Min Ragan-Kelley\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Topic :: System :: Networking", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" + ], + "requires_dist": [ + "cffi; implementation_name == \"pypy\"" + ], + "requires_python": ">=3.7", + "project_url": [ + "Homepage, https://pyzmq.readthedocs.org", + "Documentation, https://pyzmq.readthedocs.org", + "Source, https://github.com/zeromq/pyzmq", + "Tracker, https://github.com/zeromq/pyzmq/issues" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/c3/20/748e38b466e0819491f0ce6e90ebe4184966ee304fe483e2c414b0f4ef07/requests-2.32.2-py3-none-any.whl", + "archive_info": { + "hash": "sha256=fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c", + "hashes": { + "sha256": "fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "requests", + "version": "2.32.2", + "summary": "Python HTTP for Humans.", + "description": "# Requests\n\n**Requests** is a simple, yet elegant, HTTP library.\n\n```python\n>>> import requests\n>>> r = requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass'))\n>>> r.status_code\n200\n>>> r.headers['content-type']\n'application/json; charset=utf8'\n>>> r.encoding\n'utf-8'\n>>> r.text\n'{\"authenticated\": true, ...'\n>>> r.json()\n{'authenticated': True, ...}\n```\n\nRequests allows you to send HTTP/1.1 requests extremely easily. There’s no need to manually add query strings to your URLs, or to form-encode your `PUT` & `POST` data — but nowadays, just use the `json` method!\n\nRequests is one of the most downloaded Python packages today, pulling in around `30M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `1,000,000+` repositories. You may certainly put your trust in this code.\n\n[![Downloads](https://static.pepy.tech/badge/requests/month)](https://pepy.tech/project/requests)\n[![Supported Versions](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests)\n[![Contributors](https://img.shields.io/github/contributors/psf/requests.svg)](https://github.com/psf/requests/graphs/contributors)\n\n## Installing Requests and Supported Versions\n\nRequests is available on PyPI:\n\n```console\n$ python -m pip install requests\n```\n\nRequests officially supports Python 3.8+.\n\n## Supported Features & Best–Practices\n\nRequests is ready for the demands of building robust and reliable HTTP–speaking applications, for the needs of today.\n\n- Keep-Alive & Connection Pooling\n- International Domains and URLs\n- Sessions with Cookie Persistence\n- Browser-style TLS/SSL Verification\n- Basic & Digest Authentication\n- Familiar `dict`–like Cookies\n- Automatic Content Decompression and Decoding\n- Multi-part File Uploads\n- SOCKS Proxy Support\n- Connection Timeouts\n- Streaming Downloads\n- Automatic honoring of `.netrc`\n- Chunked HTTP Requests\n\n## API Reference and User Guide available on [Read the Docs](https://requests.readthedocs.io)\n\n[![Read the Docs](https://raw.githubusercontent.com/psf/requests/main/ext/ss.png)](https://requests.readthedocs.io)\n\n## Cloning the repository\n\nWhen cloning the Requests repository, you may need to add the `-c\nfetch.fsck.badTimezone=ignore` flag to avoid an error about a bad commit (see\n[this issue](https://github.com/psf/requests/issues/2690) for more background):\n\n```shell\ngit clone -c fetch.fsck.badTimezone=ignore https://github.com/psf/requests.git\n```\n\nYou can also apply this setting to your global Git config:\n\n```shell\ngit config --global fetch.fsck.badTimezone ignore\n```\n\n---\n\n[![Kenneth Reitz](https://raw.githubusercontent.com/psf/requests/main/ext/kr.png)](https://kennethreitz.org) [![Python Software Foundation](https://raw.githubusercontent.com/psf/requests/main/ext/psf.png)](https://www.python.org/psf)\n", + "description_content_type": "text/markdown", + "home_page": "https://requests.readthedocs.io", + "author": "Kenneth Reitz", + "author_email": "me@kennethreitz.org", + "license": "Apache-2.0", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Software Development :: Libraries" + ], + "requires_dist": [ + "charset-normalizer <4,>=2", + "idna <4,>=2.5", + "urllib3 <3,>=1.21.1", + "certifi >=2017.4.17", + "PySocks !=1.5.7,>=1.5.6 ; extra == 'socks'", + "chardet <6,>=3.0.2 ; extra == 'use_chardet_on_py3'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://requests.readthedocs.io", + "Source, https://github.com/psf/requests" + ], + "provides_extra": [ + "security", + "socks", + "use_chardet_on_py3" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/ba/06/a07f096c664aeb9f01624f858c3add0a4e913d6c96257acb4fce61e7de14/certifi-2024.2.2-py3-none-any.whl", + "archive_info": { + "hash": "sha256=dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1", + "hashes": { + "sha256": "dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "certifi", + "version": "2024.2.2", + "summary": "Python package for providing Mozilla's CA Bundle.", + "description": "Certifi: Python SSL Certificates\n================================\n\nCertifi provides Mozilla's carefully curated collection of Root Certificates for\nvalidating the trustworthiness of SSL certificates while verifying the identity\nof TLS hosts. It has been extracted from the `Requests`_ project.\n\nInstallation\n------------\n\n``certifi`` is available on PyPI. Simply install it with ``pip``::\n\n $ pip install certifi\n\nUsage\n-----\n\nTo reference the installed certificate authority (CA) bundle, you can use the\nbuilt-in function::\n\n >>> import certifi\n\n >>> certifi.where()\n '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem'\n\nOr from the command line::\n\n $ python -m certifi\n /usr/local/lib/python3.7/site-packages/certifi/cacert.pem\n\nEnjoy!\n\n.. _`Requests`: https://requests.readthedocs.io/en/master/\n\nAddition/Removal of Certificates\n--------------------------------\n\nCertifi does not support any addition/removal or other modification of the\nCA trust store content. This project is intended to provide a reliable and\nhighly portable root of trust to python deployments. Look to upstream projects\nfor methods to use alternate trust.\n", + "home_page": "https://github.com/certifi/python-certifi", + "author": "Kenneth Reitz", + "author_email": "me@kennethreitz.com", + "license": "MPL-2.0", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", + "Natural Language :: English", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11" + ], + "requires_python": ">=3.6", + "project_url": [ + "Source, https://github.com/certifi/python-certifi" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", + "archive_info": { + "hash": "sha256=0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", + "hashes": { + "sha256": "0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "Send2Trash", + "version": "1.8.3", + "summary": "Send file to trash natively under Mac OS X, Windows and Linux", + "description": "==================================================\r\nSend2Trash -- Send files to trash on all platforms\r\n==================================================\r\n\r\nSend2Trash is a small package that sends files to the Trash (or Recycle Bin) *natively* and on\r\n*all platforms*. On OS X, it uses native ``FSMoveObjectToTrashSync`` Cocoa calls or can use pyobjc \r\nwith NSFileManager. On Windows, it uses native ``IFileOperation`` call if on Vista or newer and \r\npywin32 is installed or falls back to ``SHFileOperation`` calls. On other platforms, if `PyGObject`_ \r\nand `GIO`_ are available, it will use this. Otherwise, it will fallback to its own implementation of \r\nthe `trash specifications from freedesktop.org`_.\r\n\r\n``ctypes`` is used to access native libraries, so no compilation is necessary.\r\n\r\nSend2Trash supports Python 2.7 and up (Python 3 is supported).\r\n\r\nStatus: Additional Help Welcome\r\n-------------------------------\r\n\r\nAdditional help is welcome for supporting this package. Specifically help with the OSX and Linux \r\nissues and fixes would be most appreciated.\r\n\r\nInstallation\r\n------------\r\n\r\nYou can download it with pip:\r\n\r\n python -m pip install -U send2trash\r\n\r\nTo install with pywin32 or pyobjc required specify the extra `nativeLib`:\r\n\r\n python -m pip install -U send2trash[nativeLib]\r\n\r\nor you can download the source from http://github.com/arsenetar/send2trash and install it with::\r\n\r\n >>> python setup.py install\r\n\r\nUsage\r\n-----\r\n\r\n>>> from send2trash import send2trash\r\n>>> send2trash('some_file')\r\n>>> send2trash(['some_file1', 'some_file2'])\r\n\r\nOn Freedesktop platforms (Linux, BSD, etc.), you may not be able to efficiently\r\ntrash some files. In these cases, an exception ``send2trash.TrashPermissionError``\r\nis raised, so that the application can handle this case. This inherits from\r\n``PermissionError`` (``OSError`` on Python 2). Specifically, this affects\r\nfiles on a different device to the user's home directory, where the root of the\r\ndevice does not have a ``.Trash`` directory, and we don't have permission to\r\ncreate a ``.Trash-$UID`` directory.\r\n\r\nFor any other problem, ``OSError`` is raised.\r\n\r\n.. _PyGObject: https://wiki.gnome.org/PyGObject\r\n.. _GIO: https://developer.gnome.org/gio/\r\n.. _trash specifications from freedesktop.org: http://freedesktop.org/wiki/Specifications/trash-spec/\r\n", + "description_content_type": "text/x-rst", + "home_page": "https://github.com/arsenetar/send2trash", + "author": "Andrew Senetar", + "author_email": "arsenetar@voltaicideas.net", + "license": "BSD License", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Desktop Environment :: File Managers" + ], + "requires_dist": [ + "pyobjc-framework-Cocoa ; (sys_platform == \"darwin\") and extra == 'nativelib'", + "pywin32 ; (sys_platform == \"win32\") and extra == 'nativelib'", + "pyobjc-framework-Cocoa ; (sys_platform == \"darwin\") and extra == 'objc'", + "pywin32 ; (sys_platform == \"win32\") and extra == 'win32'" + ], + "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7", + "project_url": [ + "Bug Reports, https://github.com/arsenetar/send2trash/issues" + ], + "provides_extra": [ + "nativelib", + "objc", + "win32" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", + "hashes": { + "sha256": "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "sniffio", + "version": "1.3.1", + "summary": "Sniff out which async library your code is running under", + "description": ".. image:: https://img.shields.io/badge/chat-join%20now-blue.svg\r\n :target: https://gitter.im/python-trio/general\r\n :alt: Join chatroom\r\n\r\n.. image:: https://img.shields.io/badge/docs-read%20now-blue.svg\r\n :target: https://sniffio.readthedocs.io/en/latest/?badge=latest\r\n :alt: Documentation Status\r\n\r\n.. image:: https://img.shields.io/pypi/v/sniffio.svg\r\n :target: https://pypi.org/project/sniffio\r\n :alt: Latest PyPi version\r\n \r\n.. image:: https://img.shields.io/conda/vn/conda-forge/sniffio.svg\r\n :target: https://anaconda.org/conda-forge/sniffio \r\n :alt: Latest conda-forge version \r\n\r\n.. image:: https://travis-ci.org/python-trio/sniffio.svg?branch=master\r\n :target: https://travis-ci.org/python-trio/sniffio\r\n :alt: Automated test status\r\n\r\n.. image:: https://codecov.io/gh/python-trio/sniffio/branch/master/graph/badge.svg\r\n :target: https://codecov.io/gh/python-trio/sniffio\r\n :alt: Test coverage\r\n\r\n=================================================================\r\nsniffio: Sniff out which async library your code is running under\r\n=================================================================\r\n\r\nYou're writing a library. You've decided to be ambitious, and support\r\nmultiple async I/O packages, like `Trio\r\n`__, and `asyncio\r\n`__, and ... You've\r\nwritten a bunch of clever code to handle all the differences. But...\r\nhow do you know *which* piece of clever code to run?\r\n\r\nThis is a tiny package whose only purpose is to let you detect which\r\nasync library your code is running under.\r\n\r\n* Documentation: https://sniffio.readthedocs.io\r\n\r\n* Bug tracker and source code: https://github.com/python-trio/sniffio\r\n\r\n* License: MIT or Apache License 2.0, your choice\r\n\r\n* Contributor guide: https://trio.readthedocs.io/en/latest/contributing.html\r\n\r\n* Code of conduct: Contributors are requested to follow our `code of\r\n conduct\r\n `_\r\n in all project spaces.\r\n\r\nThis library is maintained by the Trio project, as a service to the\r\nasync Python community as a whole.\r\n\r\n\r\nQuickstart\r\n----------\r\n\r\n.. code-block:: python3\r\n\r\n from sniffio import current_async_library\r\n import trio\r\n import asyncio\r\n\r\n async def print_library():\r\n library = current_async_library()\r\n print(\"This is:\", library)\r\n\r\n # Prints \"This is trio\"\r\n trio.run(print_library)\r\n\r\n # Prints \"This is asyncio\"\r\n asyncio.run(print_library())\r\n\r\nFor more details, including how to add support to new async libraries,\r\n`please peruse our fine manual `__.\r\n", + "description_content_type": "text/x-rst", + "keywords": [ + "async", + "trio", + "asyncio" + ], + "author_email": "\"Nathaniel J. Smith\" ", + "license": "MIT OR Apache-2.0", + "classifier": [ + "License :: OSI Approved :: MIT License", + "License :: OSI Approved :: Apache Software License", + "Framework :: Trio", + "Framework :: AsyncIO", + "Operating System :: POSIX :: Linux", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Intended Audience :: Developers", + "Development Status :: 5 - Production/Stable" + ], + "requires_python": ">=3.7", + "project_url": [ + "Homepage, https://github.com/python-trio/sniffio", + "Documentation, https://sniffio.readthedocs.io/", + "Changelog, https://sniffio.readthedocs.io/en/latest/history.html" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", + "hashes": { + "sha256": "a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "terminado", + "version": "0.18.1", + "summary": "Tornado websocket backend for the Xterm.js Javascript terminal emulator library.", + "description": "# Terminado\n\n[![Build Status](https://github.com/jupyter/terminado/actions/workflows/test.yml/badge.svg?query=branch%3Amain++)](https://github.com/jupyter/terminado/actions/workflows/test.yml/badge.svg?query=branch%3Amain++)\n[![Documentation Status](https://readthedocs.org/projects/terminado/badge/?version=latest)](http://terminado.readthedocs.io/en/latest/?badge=latest)\n\nThis is a [Tornado](http://tornadoweb.org/) websocket backend for the\n[Xterm.js](https://xtermjs.org/) Javascript terminal emulator library.\n\nIt evolved out of [pyxterm](https://github.com/mitotic/pyxterm), which\nwas part of [GraphTerm](https://github.com/mitotic/graphterm) (as\nlineterm.py), v0.57.0 (2014-07-18), and ultimately derived from the\npublic-domain [Ajaxterm](http://antony.lesuisse.org/software/ajaxterm/)\ncode, v0.11 (2008-11-13) (also on Github as part of\n[QWeb](https://github.com/antonylesuisse/qweb)).\n\nModules:\n\n- `terminado.management`: controls launching virtual terminals,\n connecting them to Tornado's event loop, and closing them down.\n- `terminado.websocket`: Provides a websocket handler for\n communicating with a terminal.\n- `terminado.uimodule`: Provides a `Terminal` Tornado [UI\n Module](http://www.tornadoweb.org/en/stable/guide/templates.html#ui-modules).\n\nJS:\n\n- `terminado/_static/terminado.js`: A lightweight wrapper to set up a\n term.js terminal with a websocket.\n\nLocal Installation:\n\n> $ pip install -e .\\[test\\]\n\nUsage example:\n\n```python\nimport os.path\nimport tornado.web\nimport tornado.ioloop\n\n# This demo requires tornado_xstatic and XStatic-term.js\nimport tornado_xstatic\n\nimport terminado\n\nSTATIC_DIR = os.path.join(os.path.dirname(terminado.__file__), \"_static\")\n\n\nclass TerminalPageHandler(tornado.web.RequestHandler):\n def get(self):\n return self.render(\n \"termpage.html\",\n static=self.static_url,\n xstatic=self.application.settings[\"xstatic_url\"],\n ws_url_path=\"/websocket\",\n )\n\n\nif __name__ == \"__main__\":\n term_manager = terminado.SingleTermManager(shell_command=[\"bash\"])\n handlers = [\n (r\"/websocket\", terminado.TermSocket, {\"term_manager\": term_manager}),\n (r\"/\", TerminalPageHandler),\n (\n r\"/xstatic/(.*)\",\n tornado_xstatic.XStaticFileHandler,\n {\"allowed_modules\": [\"termjs\"]},\n ),\n ]\n app = tornado.web.Application(\n handlers,\n static_path=STATIC_DIR,\n xstatic_url=tornado_xstatic.url_maker(\"/xstatic/\"),\n )\n # Serve at http://localhost:8765/ N.B. Leaving out 'localhost' here will\n # work, but it will listen on the public network interface as well.\n # Given what terminado does, that would be rather a security hole.\n app.listen(8765, \"localhost\")\n try:\n tornado.ioloop.IOLoop.instance().start()\n finally:\n term_manager.shutdown()\n```\n\nSee the [demos\ndirectory](https://github.com/takluyver/terminado/tree/master/demos) for\nmore examples. This is a simplified version of the `single.py` demo.\n\nRun the unit tests with:\n\n> $ pytest\n", + "description_content_type": "text/markdown", + "author_email": "Jupyter Development Team ", + "license": "BSD 2-Clause License\n\n- Copyright (c) 2014-, Jupyter development team\n- Copyright (c) 2014, Ramalingam Saravanan \n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Environment :: Web Environment", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python :: 3", + "Topic :: Terminals :: Terminal Emulators/X Terminals" + ], + "requires_dist": [ + "ptyprocess; os_name != 'nt'", + "pywinpty>=1.1.0; os_name == 'nt'", + "tornado>=6.1.0", + "myst-parser; extra == 'docs'", + "pydata-sphinx-theme; extra == 'docs'", + "sphinx; extra == 'docs'", + "pre-commit; extra == 'test'", + "pytest-timeout; extra == 'test'", + "pytest>=7.0; extra == 'test'", + "mypy~=1.6; extra == 'typing'", + "traitlets>=5.11.1; extra == 'typing'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://github.com/jupyter/terminado" + ], + "provides_extra": [ + "docs", + "test", + "typing" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", + "hashes": { + "sha256": "17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "websocket-client", + "version": "1.8.0", + "summary": "WebSocket client for Python with low level API options", + "description": "[![docs](https://readthedocs.org/projects/websocket-client/badge/?style=flat)](https://websocket-client.readthedocs.io/)\n[![Build Status](https://github.com/websocket-client/websocket-client/actions/workflows/build.yml/badge.svg)](https://github.com/websocket-client/websocket-client/actions/workflows/build.yml)\n[![codecov](https://codecov.io/gh/websocket-client/websocket-client/branch/master/graph/badge.svg?token=pcXhUQwiL3)](https://codecov.io/gh/websocket-client/websocket-client)\n[![PyPI Downloads](https://pepy.tech/badge/websocket-client)](https://pepy.tech/project/websocket-client)\n[![PyPI version](https://img.shields.io/pypi/v/websocket_client)](https://pypi.org/project/websocket_client/)\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n\n# websocket-client\n\nwebsocket-client is a WebSocket client for Python. It provides access\nto low level APIs for WebSockets. websocket-client implements version\n[hybi-13](https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-13)\nof the WebSocket protocol. This client does not currently support the\npermessage-deflate extension from\n[RFC 7692](https://tools.ietf.org/html/rfc7692).\n\n## Documentation\n\nThis project's documentation can be found at\n[https://websocket-client.readthedocs.io/](https://websocket-client.readthedocs.io/)\n\n## Contributing\n\nPlease see the [contribution guidelines](https://github.com/websocket-client/websocket-client/blob/master/CONTRIBUTING.md)\n\n## Installation\n\nYou can use `pip install websocket-client` to install, or `pip install -e .`\nto install from a local copy of the code. This module is tested on Python 3.8+.\n\nThere are several optional dependencies that can be installed to enable\nspecific websocket-client features.\n- To install `python-socks` for proxy usage and `wsaccel` for a minor performance boost, use:\n `pip install websocket-client[optional]`\n- To install `websockets` to run unit tests using the local echo server, use:\n `pip install websocket-client[test]`\n- To install `Sphinx` and `sphinx_rtd_theme` to build project documentation, use:\n `pip install websocket-client[docs]`\n\nWhile not a strict dependency, [rel](https://github.com/bubbleboy14/registeredeventlistener)\nis useful when using `run_forever` with automatic reconnect. Install rel with `pip install rel`.\n\nFootnote: Some shells, such as zsh, require you to escape the `[` and `]` characters with a `\\`.\n\n## Usage Tips\n\nCheck out the documentation's FAQ for additional guidelines:\n[https://websocket-client.readthedocs.io/en/latest/faq.html](https://websocket-client.readthedocs.io/en/latest/faq.html)\n\nKnown issues with this library include lack of WebSocket Compression\nsupport (RFC 7692) and [minimal threading documentation/support](https://websocket-client.readthedocs.io/en/latest/threading.html).\n\n## Performance\n\nThe `send` and `validate_utf8` methods can sometimes be bottleneck.\nYou can disable UTF8 validation in this library (and receive a\nperformance enhancement) with the `skip_utf8_validation` parameter.\nIf you want to get better performance, install wsaccel. While\nwebsocket-client does not depend on wsaccel, it will be used if\navailable. wsaccel doubles the speed of UTF8 validation and\noffers a very minor 10% performance boost when masking the\npayload data as part of the `send` process. Numpy used to\nbe a suggested performance enhancement alternative, but\n[issue #687](https://github.com/websocket-client/websocket-client/issues/687)\nfound it didn't help.\n\n## Examples\n\nMany more examples are found in the\n[examples documentation](https://websocket-client.readthedocs.io/en/latest/examples.html).\n\n### Long-lived Connection\n\nMost real-world WebSockets situations involve longer-lived connections.\nThe WebSocketApp `run_forever` loop will automatically try to reconnect\nto an open WebSocket connection when a network\nconnection is lost if it is provided with:\n\n- a `dispatcher` argument (async dispatcher like rel or pyevent)\n- a non-zero `reconnect` argument (delay between disconnection and attempted reconnection)\n\n`run_forever` provides a variety of event-based connection controls\nusing callbacks like `on_message` and `on_error`.\n`run_forever` **does not automatically reconnect** if the server\ncloses the WebSocket gracefully (returning\n[a standard websocket close code](https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1)).\n[This is the logic](https://github.com/websocket-client/websocket-client/pull/838#issuecomment-1228454826) behind the decision.\nCustomizing behavior when the server closes\nthe WebSocket should be handled in the `on_close` callback.\nThis example uses [rel](https://github.com/bubbleboy14/registeredeventlistener)\nfor the dispatcher to provide automatic reconnection.\n\n```python\nimport websocket\nimport _thread\nimport time\nimport rel\n\ndef on_message(ws, message):\n print(message)\n\ndef on_error(ws, error):\n print(error)\n\ndef on_close(ws, close_status_code, close_msg):\n print(\"### closed ###\")\n\ndef on_open(ws):\n print(\"Opened connection\")\n\nif __name__ == \"__main__\":\n websocket.enableTrace(True)\n ws = websocket.WebSocketApp(\"wss://api.gemini.com/v1/marketdata/BTCUSD\",\n on_open=on_open,\n on_message=on_message,\n on_error=on_error,\n on_close=on_close)\n\n ws.run_forever(dispatcher=rel, reconnect=5) # Set dispatcher to automatic reconnection, 5 second reconnect delay if connection closed unexpectedly\n rel.signal(2, rel.abort) # Keyboard Interrupt\n rel.dispatch()\n```\n\n### Short-lived Connection\n\nThis is if you want to communicate a short message and disconnect\nimmediately when done. For example, if you want to confirm that a WebSocket\nserver is running and responds properly to a specific request.\n\n```python\nfrom websocket import create_connection\n\nws = create_connection(\"ws://echo.websocket.events/\")\nprint(ws.recv())\nprint(\"Sending 'Hello, World'...\")\nws.send(\"Hello, World\")\nprint(\"Sent\")\nprint(\"Receiving...\")\nresult = ws.recv()\nprint(\"Received '%s'\" % result)\nws.close()\n```\n", + "description_content_type": "text/markdown", + "keywords": [ + "websockets", + "client" + ], + "home_page": "https://github.com/websocket-client/websocket-client.git", + "download_url": "https://github.com/websocket-client/websocket-client/releases", + "author": "liris", + "author_email": "liris.pp@gmail.com", + "maintainer": "engn33r", + "maintainer_email": "websocket.client@proton.me", + "license": "Apache-2.0", + "classifier": [ + "Development Status :: 4 - Beta", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Operating System :: MacOS :: MacOS X", + "Operating System :: POSIX", + "Operating System :: Microsoft :: Windows", + "Topic :: Internet", + "Topic :: Software Development :: Libraries :: Python Modules", + "Intended Audience :: Developers" + ], + "requires_dist": [ + "Sphinx >=6.0 ; extra == 'docs'", + "sphinx-rtd-theme >=1.1.0 ; extra == 'docs'", + "myst-parser >=2.0.0 ; extra == 'docs'", + "python-socks ; extra == 'optional'", + "wsaccel ; extra == 'optional'", + "websockets ; extra == 'test'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://websocket-client.readthedocs.io/", + "Source, https://github.com/websocket-client/websocket-client/" + ], + "provides_extra": [ + "docs", + "optional", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", + "hashes": { + "sha256": "87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "nest-asyncio", + "version": "1.6.0", + "summary": "Patch asyncio to allow nested event loops", + "description": "|Build| |Status| |PyPiVersion| |License| |Downloads|\n\nIntroduction\n------------\n\nBy design asyncio `does not allow `_\nits event loop to be nested. This presents a practical problem:\nWhen in an environment where the event loop is\nalready running it's impossible to run tasks and wait\nfor the result. Trying to do so will give the error\n\"``RuntimeError: This event loop is already running``\".\n\nThe issue pops up in various environments, such as web servers,\nGUI applications and in Jupyter notebooks.\n\nThis module patches asyncio to allow nested use of ``asyncio.run`` and\n``loop.run_until_complete``.\n\nInstallation\n------------\n\n.. code-block::\n\n pip3 install nest_asyncio\n\nPython 3.5 or higher is required.\n\nUsage\n-----\n\n.. code-block:: python\n\n import nest_asyncio\n nest_asyncio.apply()\n\nOptionally the specific loop that needs patching can be given\nas argument to ``apply``, otherwise the current event loop is used.\nAn event loop can be patched whether it is already running\nor not. Only event loops from asyncio can be patched;\nLoops from other projects, such as uvloop or quamash,\ngenerally can't be patched.\n\n\n.. |Build| image:: https://github.com/erdewit/nest_asyncio/actions/workflows/test.yml/badge.svg?branche=master\n :alt: Build\n :target: https://github.com/erdewit/nest_asyncio/actions\n\n.. |PyPiVersion| image:: https://img.shields.io/pypi/v/nest_asyncio.svg\n :alt: PyPi\n :target: https://pypi.python.org/pypi/nest_asyncio\n\n.. |Status| image:: https://img.shields.io/badge/status-stable-green.svg\n :alt:\n\n.. |License| image:: https://img.shields.io/badge/license-BSD-blue.svg\n :alt:\n\n.. |Downloads| image:: https://static.pepy.tech/badge/nest-asyncio/month\n :alt: Number of downloads\n :target: https://pepy.tech/project/nest-asyncio\n\n", + "description_content_type": "text/x-rst", + "keywords": [ + "asyncio", + "nested", + "eventloop" + ], + "home_page": "https://github.com/erdewit/nest_asyncio", + "author": "Ewald R. de Wit", + "author_email": "ewald.de.wit@gmail.com", + "license": "BSD", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3 :: Only", + "Framework :: AsyncIO" + ], + "requires_python": ">=3.5" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/93/52/3e39d26feae7df0aa0fd510b14012c3678b36ed068f7d78b8d8784d61f0e/psutil-5.9.8-cp37-abi3-win_amd64.whl", + "archive_info": { + "hash": "sha256=8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf", + "hashes": { + "sha256": "8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "psutil", + "version": "5.9.8", + "platform": [ + "Platform Independent" + ], + "summary": "Cross-platform lib for process and system monitoring in Python.", + "description": "| |downloads| |stars| |forks| |contributors| |coverage|\r\n| |version| |py-versions| |packages| |license|\r\n| |github-actions-wheels| |github-actions-bsd| |appveyor| |doc| |twitter| |tidelift|\r\n\r\n.. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg\r\n :target: https://pepy.tech/project/psutil\r\n :alt: Downloads\r\n\r\n.. |stars| image:: https://img.shields.io/github/stars/giampaolo/psutil.svg\r\n :target: https://github.com/giampaolo/psutil/stargazers\r\n :alt: Github stars\r\n\r\n.. |forks| image:: https://img.shields.io/github/forks/giampaolo/psutil.svg\r\n :target: https://github.com/giampaolo/psutil/network/members\r\n :alt: Github forks\r\n\r\n.. |contributors| image:: https://img.shields.io/github/contributors/giampaolo/psutil.svg\r\n :target: https://github.com/giampaolo/psutil/graphs/contributors\r\n :alt: Contributors\r\n\r\n.. |github-actions-wheels| image:: https://img.shields.io/github/actions/workflow/status/giampaolo/psutil/.github/workflows/build.yml?label=Linux%2C%20macOS%2C%20Windows\r\n :target: https://github.com/giampaolo/psutil/actions?query=workflow%3Abuild\r\n :alt: Linux, macOS, Windows\r\n\r\n.. |github-actions-bsd| image:: https://img.shields.io/github/actions/workflow/status/giampaolo/psutil/.github/workflows/bsd.yml?label=FreeBSD,%20NetBSD,%20OpenBSD\r\n :target: https://github.com/giampaolo/psutil/actions?query=workflow%3Absd-tests\r\n :alt: FreeBSD, NetBSD, OpenBSD\r\n\r\n.. |appveyor| image:: https://img.shields.io/appveyor/build/giampaolo/psutil/master.svg?maxAge=3600&label=Windows%20(py2)\r\n :target: https://ci.appveyor.com/project/giampaolo/psutil\r\n :alt: Windows (Appveyor)\r\n\r\n.. |coverage| image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master\r\n :target: https://coveralls.io/github/giampaolo/psutil?branch=master\r\n :alt: Test coverage (coverall.io)\r\n\r\n.. |doc| image:: https://readthedocs.org/projects/psutil/badge/?version=latest\r\n :target: https://psutil.readthedocs.io/en/latest/\r\n :alt: Documentation Status\r\n\r\n.. |version| image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi\r\n :target: https://pypi.org/project/psutil\r\n :alt: Latest version\r\n\r\n.. |py-versions| image:: https://img.shields.io/pypi/pyversions/psutil.svg\r\n :alt: Supported Python versions\r\n\r\n.. |packages| image:: https://repology.org/badge/tiny-repos/python:psutil.svg\r\n :target: https://repology.org/metapackage/python:psutil/versions\r\n :alt: Binary packages\r\n\r\n.. |license| image:: https://img.shields.io/pypi/l/psutil.svg\r\n :target: https://github.com/giampaolo/psutil/blob/master/LICENSE\r\n :alt: License\r\n\r\n.. |twitter| image:: https://img.shields.io/twitter/follow/grodola.svg?label=follow&style=flat&logo=twitter&logoColor=4FADFF\r\n :target: https://twitter.com/grodola\r\n :alt: Twitter Follow\r\n\r\n.. |tidelift| image:: https://tidelift.com/badges/github/giampaolo/psutil?style=flat\r\n :target: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme\r\n :alt: Tidelift\r\n\r\n-----\r\n\r\nQuick links\r\n===========\r\n\r\n- `Home page `_\r\n- `Install `_\r\n- `Documentation `_\r\n- `Download `_\r\n- `Forum `_\r\n- `StackOverflow `_\r\n- `Blog `_\r\n- `What's new `_\r\n\r\n\r\nSummary\r\n=======\r\n\r\npsutil (process and system utilities) is a cross-platform library for\r\nretrieving information on **running processes** and **system utilization**\r\n(CPU, memory, disks, network, sensors) in Python.\r\nIt is useful mainly for **system monitoring**, **profiling and limiting process\r\nresources** and **management of running processes**.\r\nIt implements many functionalities offered by classic UNIX command line tools\r\nsuch as *ps, top, iotop, lsof, netstat, ifconfig, free* and others.\r\npsutil currently supports the following platforms:\r\n\r\n- **Linux**\r\n- **Windows**\r\n- **macOS**\r\n- **FreeBSD, OpenBSD**, **NetBSD**\r\n- **Sun Solaris**\r\n- **AIX**\r\n\r\nSupported Python versions are **2.7**, **3.6+** and\r\n`PyPy `__.\r\n\r\nFunding\r\n=======\r\n\r\nWhile psutil is free software and will always be, the project would benefit\r\nimmensely from some funding.\r\nKeeping up with bug reports and maintenance has become hardly sustainable for\r\nme alone in terms of time.\r\nIf you're a company that's making significant use of psutil you can consider\r\nbecoming a sponsor via `GitHub Sponsors `__,\r\n`Open Collective `__ or\r\n`PayPal `__\r\nand have your logo displayed in here and psutil `doc `__.\r\n\r\nSponsors\r\n========\r\n\r\n.. image:: https://github.com/giampaolo/psutil/raw/master/docs/_static/tidelift-logo.png\r\n :width: 200\r\n :alt: Alternative text\r\n\r\n`Add your logo `__.\r\n\r\nExample usages\r\n==============\r\n\r\nThis represents pretty much the whole psutil API.\r\n\r\nCPU\r\n---\r\n\r\n.. code-block:: python\r\n\r\n >>> import psutil\r\n >>>\r\n >>> psutil.cpu_times()\r\n scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, guest_nice=0.0)\r\n >>>\r\n >>> for x in range(3):\r\n ... psutil.cpu_percent(interval=1)\r\n ...\r\n 4.0\r\n 5.9\r\n 3.8\r\n >>>\r\n >>> for x in range(3):\r\n ... psutil.cpu_percent(interval=1, percpu=True)\r\n ...\r\n [4.0, 6.9, 3.7, 9.2]\r\n [7.0, 8.5, 2.4, 2.1]\r\n [1.2, 9.0, 9.9, 7.2]\r\n >>>\r\n >>> for x in range(3):\r\n ... psutil.cpu_times_percent(interval=1, percpu=False)\r\n ...\r\n scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)\r\n scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)\r\n scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)\r\n >>>\r\n >>> psutil.cpu_count()\r\n 4\r\n >>> psutil.cpu_count(logical=False)\r\n 2\r\n >>>\r\n >>> psutil.cpu_stats()\r\n scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)\r\n >>>\r\n >>> psutil.cpu_freq()\r\n scpufreq(current=931.42925, min=800.0, max=3500.0)\r\n >>>\r\n >>> psutil.getloadavg() # also on Windows (emulated)\r\n (3.14, 3.89, 4.67)\r\n\r\nMemory\r\n------\r\n\r\n.. code-block:: python\r\n\r\n >>> psutil.virtual_memory()\r\n svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)\r\n >>> psutil.swap_memory()\r\n sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)\r\n >>>\r\n\r\nDisks\r\n-----\r\n\r\n.. code-block:: python\r\n\r\n >>> psutil.disk_partitions()\r\n [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid', maxfile=255, maxpath=4096),\r\n sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext', opts='rw', maxfile=255, maxpath=4096)]\r\n >>>\r\n >>> psutil.disk_usage('/')\r\n sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)\r\n >>>\r\n >>> psutil.disk_io_counters(perdisk=False)\r\n sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)\r\n >>>\r\n\r\nNetwork\r\n-------\r\n\r\n.. code-block:: python\r\n\r\n >>> psutil.net_io_counters(pernic=True)\r\n {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),\r\n 'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}\r\n >>>\r\n >>> psutil.net_connections(kind='tcp')\r\n [sconn(fd=115, family=, type=, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),\r\n sconn(fd=117, family=, type=, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),\r\n ...]\r\n >>>\r\n >>> psutil.net_if_addrs()\r\n {'lo': [snicaddr(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),\r\n snicaddr(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),\r\n snicaddr(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],\r\n 'wlan0': [snicaddr(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),\r\n snicaddr(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),\r\n snicaddr(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}\r\n >>>\r\n >>> psutil.net_if_stats()\r\n {'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536, flags='up,loopback,running'),\r\n 'wlan0': snicstats(isup=True, duplex=, speed=100, mtu=1500, flags='up,broadcast,running,multicast')}\r\n >>>\r\n\r\nSensors\r\n-------\r\n\r\n.. code-block:: python\r\n\r\n >>> import psutil\r\n >>> psutil.sensors_temperatures()\r\n {'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],\r\n 'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],\r\n 'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),\r\n shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0)]}\r\n >>>\r\n >>> psutil.sensors_fans()\r\n {'asus': [sfan(label='cpu_fan', current=3200)]}\r\n >>>\r\n >>> psutil.sensors_battery()\r\n sbattery(percent=93, secsleft=16628, power_plugged=False)\r\n >>>\r\n\r\nOther system info\r\n-----------------\r\n\r\n.. code-block:: python\r\n\r\n >>> import psutil\r\n >>> psutil.users()\r\n [suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),\r\n suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]\r\n >>>\r\n >>> psutil.boot_time()\r\n 1365519115.0\r\n >>>\r\n\r\nProcess management\r\n------------------\r\n\r\n.. code-block:: python\r\n\r\n >>> import psutil\r\n >>> psutil.pids()\r\n [1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215,\r\n 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355, 2637, 2774, 3932,\r\n 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282, 4306, 4311,\r\n 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433,\r\n 4443, 4445, 4446, 5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054,\r\n 7055, 7071]\r\n >>>\r\n >>> p = psutil.Process(7055)\r\n >>> p\r\n psutil.Process(pid=7055, name='python3', status='running', started='09:04:44')\r\n >>> p.pid\r\n 7055\r\n >>> p.name()\r\n 'python3'\r\n >>> p.exe()\r\n '/usr/bin/python3'\r\n >>> p.cwd()\r\n '/home/giampaolo'\r\n >>> p.cmdline()\r\n ['/usr/bin/python3', 'main.py']\r\n >>>\r\n >>> p.ppid()\r\n 7054\r\n >>> p.parent()\r\n psutil.Process(pid=4699, name='bash', status='sleeping', started='09:06:44')\r\n >>> p.parents()\r\n [psutil.Process(pid=4699, name='bash', started='09:06:44'),\r\n psutil.Process(pid=4689, name='gnome-terminal-server', status='sleeping', started='0:06:44'),\r\n psutil.Process(pid=1, name='systemd', status='sleeping', started='05:56:55')]\r\n >>> p.children(recursive=True)\r\n [psutil.Process(pid=29835, name='python3', status='sleeping', started='11:45:38'),\r\n psutil.Process(pid=29836, name='python3', status='waking', started='11:43:39')]\r\n >>>\r\n >>> p.status()\r\n 'running'\r\n >>> p.create_time()\r\n 1267551141.5019531\r\n >>> p.terminal()\r\n '/dev/pts/0'\r\n >>>\r\n >>> p.username()\r\n 'giampaolo'\r\n >>> p.uids()\r\n puids(real=1000, effective=1000, saved=1000)\r\n >>> p.gids()\r\n pgids(real=1000, effective=1000, saved=1000)\r\n >>>\r\n >>> p.cpu_times()\r\n pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1, iowait=0.0)\r\n >>> p.cpu_percent(interval=1.0)\r\n 12.1\r\n >>> p.cpu_affinity()\r\n [0, 1, 2, 3]\r\n >>> p.cpu_affinity([0, 1]) # set\r\n >>> p.cpu_num()\r\n 1\r\n >>>\r\n >>> p.memory_info()\r\n pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)\r\n >>> p.memory_full_info() # \"real\" USS memory usage (Linux, macOS, Win only)\r\n pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)\r\n >>> p.memory_percent()\r\n 0.7823\r\n >>> p.memory_maps()\r\n [pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),\r\n pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),\r\n pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),\r\n pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),\r\n ...]\r\n >>>\r\n >>> p.io_counters()\r\n pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)\r\n >>>\r\n >>> p.open_files()\r\n [popenfile(path='/home/giampaolo/monit.py', fd=3, position=0, mode='r', flags=32768),\r\n popenfile(path='/var/log/monit.log', fd=4, position=235542, mode='a', flags=33793)]\r\n >>>\r\n >>> p.connections(kind='tcp')\r\n [pconn(fd=115, family=, type=, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),\r\n pconn(fd=117, family=, type=, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING')]\r\n >>>\r\n >>> p.threads()\r\n [pthread(id=5234, user_time=22.5, system_time=9.2891),\r\n pthread(id=5237, user_time=0.0707, system_time=1.1)]\r\n >>>\r\n >>> p.num_threads()\r\n 4\r\n >>> p.num_fds()\r\n 8\r\n >>> p.num_ctx_switches()\r\n pctxsw(voluntary=78, involuntary=19)\r\n >>>\r\n >>> p.nice()\r\n 0\r\n >>> p.nice(10) # set\r\n >>>\r\n >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)\r\n >>> p.ionice()\r\n pionice(ioclass=, value=0)\r\n >>>\r\n >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only)\r\n >>> p.rlimit(psutil.RLIMIT_NOFILE)\r\n (5, 5)\r\n >>>\r\n >>> p.environ()\r\n {'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',\r\n 'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg',\r\n ...}\r\n >>>\r\n >>> p.as_dict()\r\n {'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}\r\n >>> p.is_running()\r\n True\r\n >>> p.suspend()\r\n >>> p.resume()\r\n >>>\r\n >>> p.terminate()\r\n >>> p.kill()\r\n >>> p.wait(timeout=3)\r\n \r\n >>>\r\n >>> psutil.test()\r\n USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND\r\n root 1 0.0 0.0 24584 2240 Jun17 00:00 init\r\n root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd\r\n ...\r\n giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4\r\n giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome\r\n root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1\r\n >>>\r\n\r\nFurther process APIs\r\n--------------------\r\n\r\n.. code-block:: python\r\n\r\n >>> import psutil\r\n >>> for proc in psutil.process_iter(['pid', 'name']):\r\n ... print(proc.info)\r\n ...\r\n {'pid': 1, 'name': 'systemd'}\r\n {'pid': 2, 'name': 'kthreadd'}\r\n {'pid': 3, 'name': 'ksoftirqd/0'}\r\n ...\r\n >>>\r\n >>> psutil.pid_exists(3)\r\n True\r\n >>>\r\n >>> def on_terminate(proc):\r\n ... print(\"process {} terminated\".format(proc))\r\n ...\r\n >>> # waits for multiple processes to terminate\r\n >>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)\r\n >>>\r\n\r\nWindows services\r\n----------------\r\n\r\n.. code-block:: python\r\n\r\n >>> list(psutil.win_service_iter())\r\n [,\r\n ,\r\n ,\r\n ,\r\n ...]\r\n >>> s = psutil.win_service_get('alg')\r\n >>> s.as_dict()\r\n {'binpath': 'C:\\\\Windows\\\\System32\\\\alg.exe',\r\n 'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',\r\n 'display_name': 'Application Layer Gateway Service',\r\n 'name': 'alg',\r\n 'pid': None,\r\n 'start_type': 'manual',\r\n 'status': 'stopped',\r\n 'username': 'NT AUTHORITY\\\\LocalService'}\r\n\r\nProjects using psutil\r\n=====================\r\n\r\nHere's some I find particularly interesting:\r\n\r\n- https://github.com/google/grr\r\n- https://github.com/facebook/osquery/\r\n- https://github.com/nicolargo/glances\r\n- https://github.com/aristocratos/bpytop\r\n- https://github.com/Jahaja/psdash\r\n- https://github.com/ajenti/ajenti\r\n- https://github.com/home-assistant/home-assistant/\r\n\r\nPortings\r\n========\r\n\r\n- Go: https://github.com/shirou/gopsutil\r\n- C: https://github.com/hamon-in/cpslib\r\n- Rust: https://github.com/rust-psutil/rust-psutil\r\n- Nim: https://github.com/johnscillieri/psutil-nim\r\n\r\n", + "description_content_type": "text/x-rst", + "keywords": [ + "ps", + "top", + "kill", + "free", + "lsof", + "netstat", + "nice", + "tty", + "ionice", + "uptime", + "taskmgr", + "process", + "df", + "iotop", + "iostat", + "ifconfig", + "taskset", + "who", + "pidof", + "pmap", + "smem", + "pstree", + "monitoring", + "ulimit", + "prlimit", + "smem", + "performance", + "metrics", + "agent", + "observability" + ], + "home_page": "https://github.com/giampaolo/psutil", + "author": "Giampaolo Rodola", + "author_email": "g.rodola@gmail.com", + "license": "BSD-3-Clause", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Environment :: Win32 (MS Windows)", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows :: Windows 10", + "Operating System :: Microsoft :: Windows :: Windows 7", + "Operating System :: Microsoft :: Windows :: Windows 8", + "Operating System :: Microsoft :: Windows :: Windows 8.1", + "Operating System :: Microsoft :: Windows :: Windows Server 2003", + "Operating System :: Microsoft :: Windows :: Windows Server 2008", + "Operating System :: Microsoft :: Windows :: Windows Vista", + "Operating System :: Microsoft", + "Operating System :: OS Independent", + "Operating System :: POSIX :: AIX", + "Operating System :: POSIX :: BSD :: FreeBSD", + "Operating System :: POSIX :: BSD :: NetBSD", + "Operating System :: POSIX :: BSD :: OpenBSD", + "Operating System :: POSIX :: BSD", + "Operating System :: POSIX :: Linux", + "Operating System :: POSIX :: SunOS/Solaris", + "Operating System :: POSIX", + "Programming Language :: C", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Programming Language :: Python", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Libraries", + "Topic :: System :: Benchmark", + "Topic :: System :: Hardware :: Hardware Drivers", + "Topic :: System :: Hardware", + "Topic :: System :: Monitoring", + "Topic :: System :: Networking :: Monitoring :: Hardware Watchdog", + "Topic :: System :: Networking :: Monitoring", + "Topic :: System :: Networking", + "Topic :: System :: Operating System", + "Topic :: System :: Systems Administration", + "Topic :: Utilities" + ], + "requires_dist": [ + "ipaddress ; (python_version < \"3.0\") and extra == 'test'", + "mock ; (python_version < \"3.0\") and extra == 'test'", + "enum34 ; (python_version <= \"3.4\") and extra == 'test'", + "pywin32 ; (sys_platform == \"win32\") and extra == 'test'", + "wmi ; (sys_platform == \"win32\") and extra == 'test'" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*", + "provides_extra": [ + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1", + "hashes": { + "sha256": "99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "attrs", + "version": "23.2.0", + "summary": "Classes Without Boilerplate", + "description": "

\n \n \"attrs\"\n \n

\n\n\n*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)).\n[Trusted by NASA](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/personalizing-your-profile#list-of-qualifying-repositories-for-mars-2020-helicopter-contributor-achievement) for Mars missions since 2020!\n\nIts main goal is to help you to write **concise** and **correct** software without slowing down your code.\n\n\n## Sponsors\n\n*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek).\nEspecially those generously supporting us at the *The Organization* tier and higher:\n\n

\n \n \n \n

\n\n

\n Please consider joining them to help make attrs’s maintenance more sustainable!\n

\n\n\n\n## Example\n\n*attrs* gives you a class decorator and a way to declaratively define the attributes on that class:\n\n\n\n```pycon\n>>> from attrs import asdict, define, make_class, Factory\n\n>>> @define\n... class SomeClass:\n... a_number: int = 42\n... list_of_numbers: list[int] = Factory(list)\n...\n... def hard_math(self, another_number):\n... return self.a_number + sum(self.list_of_numbers) * another_number\n\n\n>>> sc = SomeClass(1, [1, 2, 3])\n>>> sc\nSomeClass(a_number=1, list_of_numbers=[1, 2, 3])\n\n>>> sc.hard_math(3)\n19\n>>> sc == SomeClass(1, [1, 2, 3])\nTrue\n>>> sc != SomeClass(2, [3, 2, 1])\nTrue\n\n>>> asdict(sc)\n{'a_number': 1, 'list_of_numbers': [1, 2, 3]}\n\n>>> SomeClass()\nSomeClass(a_number=42, list_of_numbers=[])\n\n>>> C = make_class(\"C\", [\"a\", \"b\"])\n>>> C(\"foo\", \"bar\")\nC(a='foo', b='bar')\n```\n\nAfter *declaring* your attributes, *attrs* gives you:\n\n- a concise and explicit overview of the class's attributes,\n- a nice human-readable `__repr__`,\n- equality-checking methods,\n- an initializer,\n- and much more,\n\n*without* writing dull boilerplate code again and again and *without* runtime performance penalties.\n\n**Hate type annotations**!?\nNo problem!\nTypes are entirely **optional** with *attrs*.\nSimply assign `attrs.field()` to the attributes instead of annotating them with types.\n\n---\n\nThis example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0.\nThe classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**.\n\nPlease check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for a more in-depth explanation.\n\n\n## Data Classes\n\nOn the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*).\nIn practice it does a lot more and is more flexible.\nFor instance it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), and allows for stepping through the generated methods using a debugger.\n\nFor more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes).\n\n\n## Project Information\n\n- [**Changelog**](https://www.attrs.org/en/stable/changelog.html)\n- [**Documentation**](https://www.attrs.org/)\n- [**PyPI**](https://pypi.org/project/attrs/)\n- [**Source Code**](https://github.com/python-attrs/attrs)\n- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md)\n- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs)\n- **Get Help**: please use the `python-attrs` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/python-attrs)\n\n\n### *attrs* for Enterprise\n\nAvailable as part of the Tidelift Subscription.\n\nThe maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications.\nSave time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.\n[Learn more.](https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)\n\n## Release Information\n\n### Changes\n\n- The type annotation for `attrs.resolve_types()` is now correct.\n [#1141](https://github.com/python-attrs/attrs/issues/1141)\n- Type stubs now use `typing.dataclass_transform` to decorate dataclass-like decorators, instead of the non-standard `__dataclass_transform__` special form, which is only supported by Pyright.\n [#1158](https://github.com/python-attrs/attrs/issues/1158)\n- Fixed serialization of namedtuple fields using `attrs.asdict/astuple()` with `retain_collection_types=True`.\n [#1165](https://github.com/python-attrs/attrs/issues/1165)\n- `attrs.AttrsInstance` is now a `typing.Protocol` in both type hints and code.\n This allows you to subclass it along with another `Protocol`.\n [#1172](https://github.com/python-attrs/attrs/issues/1172)\n- If *attrs* detects that `__attrs_pre_init__` accepts more than just `self`, it will call it with the same arguments as `__init__` was called.\n This allows you to, for example, pass arguments to `super().__init__()`.\n [#1187](https://github.com/python-attrs/attrs/issues/1187)\n- Slotted classes now transform `functools.cached_property` decorated methods to support equivalent semantics.\n [#1200](https://github.com/python-attrs/attrs/issues/1200)\n- Added *class_body* argument to `attrs.make_class()` to provide additional attributes for newly created classes.\n It is, for example, now possible to attach methods.\n [#1203](https://github.com/python-attrs/attrs/issues/1203)\n\n\n---\n\n[Full changelog](https://www.attrs.org/en/stable/changelog.html)\n", + "description_content_type": "text/markdown", + "keywords": [ + "attribute", + "boilerplate", + "class" + ], + "author_email": "Hynek Schlawack ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Typing :: Typed" + ], + "requires_dist": [ + "importlib-metadata; python_version < '3.8'", + "attrs[tests]; extra == 'cov'", + "coverage[toml]>=5.3; extra == 'cov'", + "attrs[tests]; extra == 'dev'", + "pre-commit; extra == 'dev'", + "furo; extra == 'docs'", + "myst-parser; extra == 'docs'", + "sphinx; extra == 'docs'", + "sphinx-notfound-page; extra == 'docs'", + "sphinxcontrib-towncrier; extra == 'docs'", + "towncrier; extra == 'docs'", + "zope-interface; extra == 'docs'", + "attrs[tests-no-zope]; extra == 'tests'", + "zope-interface; extra == 'tests'", + "mypy>=1.6; (platform_python_implementation == 'CPython' and python_version >= '3.8') and extra == 'tests-mypy'", + "pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.8') and extra == 'tests-mypy'", + "attrs[tests-mypy]; extra == 'tests-no-zope'", + "cloudpickle; (platform_python_implementation == 'CPython') and extra == 'tests-no-zope'", + "hypothesis; extra == 'tests-no-zope'", + "pympler; extra == 'tests-no-zope'", + "pytest-xdist[psutil]; extra == 'tests-no-zope'", + "pytest>=4.3.0; extra == 'tests-no-zope'" + ], + "requires_python": ">=3.7", + "project_url": [ + "Documentation, https://www.attrs.org/", + "Changelog, https://www.attrs.org/en/stable/changelog.html", + "GitHub, https://github.com/python-attrs/attrs", + "Funding, https://github.com/sponsors/hynek", + "Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi" + ], + "provides_extra": [ + "cov", + "dev", + "docs", + "tests", + "tests-mypy", + "tests-no-zope" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/ea/63/da7237f805089ecc28a3f36bca6a21c31fcbc2eb380f3b8f1be3312abd14/bleach-6.1.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6", + "hashes": { + "sha256": "3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "bleach", + "version": "6.1.0", + "summary": "An easy safelist-based HTML-sanitizing tool.", + "description": "======\nBleach\n======\n\n.. image:: https://github.com/mozilla/bleach/workflows/Test/badge.svg\n :target: https://github.com/mozilla/bleach/actions?query=workflow%3ATest\n\n.. image:: https://github.com/mozilla/bleach/workflows/Lint/badge.svg\n :target: https://github.com/mozilla/bleach/actions?query=workflow%3ALint\n\n.. image:: https://badge.fury.io/py/bleach.svg\n :target: http://badge.fury.io/py/bleach\n\n**NOTE: 2023-01-23: Bleach is deprecated.** See issue:\n``__\n\nBleach is an allowed-list-based HTML sanitizing library that escapes or strips\nmarkup and attributes.\n\nBleach can also linkify text safely, applying filters that Django's ``urlize``\nfilter cannot, and optionally setting ``rel`` attributes, even on links already\nin the text.\n\nBleach is intended for sanitizing text from *untrusted* sources. If you find\nyourself jumping through hoops to allow your site administrators to do lots of\nthings, you're probably outside the use cases. Either trust those users, or\ndon't.\n\nBecause it relies on html5lib_, Bleach is as good as modern browsers at dealing\nwith weird, quirky HTML fragments. And *any* of Bleach's methods will fix\nunbalanced or mis-nested tags.\n\nThe version on GitHub_ is the most up-to-date and contains the latest bug\nfixes. You can find full documentation on `ReadTheDocs`_.\n\n:Code: https://github.com/mozilla/bleach\n:Documentation: https://bleach.readthedocs.io/\n:Issue tracker: https://github.com/mozilla/bleach/issues\n:License: Apache License v2; see LICENSE file\n\n\nReporting Bugs\n==============\n\nFor regular bugs, please report them `in our issue tracker\n`_.\n\nIf you believe that you've found a security vulnerability, please `file a secure\nbug report in our bug tracker\n`_\nor send an email to *security AT mozilla DOT org*.\n\nFor more information on security-related bug disclosure and the PGP key to use\nfor sending encrypted mail or to verify responses received from that address,\nplease read our wiki page at\n``_.\n\n\nSecurity\n========\n\nBleach is a security-focused library.\n\nWe have a responsible security vulnerability reporting process. Please use\nthat if you're reporting a security issue.\n\nSecurity issues are fixed in private. After we land such a fix, we'll do a\nrelease.\n\nFor every release, we mark security issues we've fixed in the ``CHANGES`` in\nthe **Security issues** section. We include any relevant CVE links.\n\n\nInstalling Bleach\n=================\n\nBleach is available on PyPI_, so you can install it with ``pip``::\n\n $ pip install bleach\n\n\nUpgrading Bleach\n================\n\n.. warning::\n\n Before doing any upgrades, read through `Bleach Changes\n `_ for backwards\n incompatible changes, newer versions, etc.\n\n Bleach follows `semver 2`_ versioning. Vendored libraries will not\n be changed in patch releases.\n\n\nBasic use\n=========\n\nThe simplest way to use Bleach is:\n\n.. code-block:: python\n\n >>> import bleach\n\n >>> bleach.clean('an example')\n u'an <script>evil()</script> example'\n\n >>> bleach.linkify('an http://example.com url')\n u'an http://example.com url'\n\n\nCode of Conduct\n===============\n\nThis project and repository is governed by Mozilla's code of conduct and\netiquette guidelines. For more details please see the `CODE_OF_CONDUCT.md\n`_\n\n\n.. _html5lib: https://github.com/html5lib/html5lib-python\n.. _GitHub: https://github.com/mozilla/bleach\n.. _ReadTheDocs: https://bleach.readthedocs.io/\n.. _PyPI: https://pypi.org/project/bleach/\n.. _semver 2: https://semver.org/\n\n\nBleach changes\n==============\n\nVersion 6.1.0 (October 6th, 2023)\n---------------------------------\n\n**Backwards incompatible changes**\n\n* Dropped support for Python 3.7. (#709)\n\n**Security fixes**\n\nNone\n\n**Bug fixes**\n\n* Add support for Python 3.12. (#710)\n* Fix linkify with arrays in querystring (#436)\n* Handle more cases with < followed by character data (#705)\n* Fix entities inside a tags in linkification (#704)\n* Update cap for tinycss2 to <1.3 (#702)\n* Updated Sphinx requirement\n* Add dependabot for github actions and update github actions\n\n\nVersion 6.0.0 (January 23rd, 2023)\n----------------------------------\n\n**Backwards incompatible changes**\n\n* ``bleach.clean``, ``bleach.sanitizer.Cleaner``,\n ``bleach.html5lib_shim.BleachHTMLParser``: the ``tags`` and ``protocols``\n arguments were changed from lists to sets.\n\n Old pre-6.0.0:\n\n .. code-block:: python\n\n bleach.clean(\n \"some text\",\n tags=[\"a\", \"p\", \"img\"],\n # ^ ^ list\n protocols=[\"http\", \"https\"],\n # ^ ^ list\n )\n\n\n New 6.0.0 and later:\n\n .. code-block:: python\n\n bleach.clean(\n \"some text\",\n tags={\"a\", \"p\", \"img\"},\n # ^ ^ set\n protocols={\"http\", \"https\"},\n # ^ ^ set\n )\n\n* ``bleach.linkify``, ``bleach.linkifier.Linker``: the ``skip_tags`` and\n ``recognized_tags`` arguments were changed from lists to sets.\n\n Old pre-6.0.0:\n\n .. code-block:: python\n\n bleach.linkify(\n \"some text\",\n skip_tags=[\"pre\"],\n # ^ ^ list\n )\n\n linker = Linker(\n skip_tags=[\"pre\"],\n # ^ ^ list\n recognized_tags=html5lib_shim.HTML_TAGS + [\"custom-element\"],\n # ^ ^ ^ list\n # |\n # | list concatenation\n )\n\n New 6.0.0 and later:\n\n .. code-block:: python\n\n bleach.linkify(\n \"some text\",\n skip_tags={\"pre\"},\n # ^ ^ set\n )\n\n linker = Linker(\n skip_tags={\"pre\"},\n # ^ ^ set\n recognized_tags=html5lib_shim.HTML_TAGS | {\"custom-element\"},\n # ^ ^ ^ set\n # |\n # | union operator\n )\n\n* ``bleach.sanitizer.BleachSanitizerFilter``: ``strip_allowed_elements`` is now\n ``strip_allowed_tags``. We now use \"tags\" everywhere rather than a mishmash\n of \"tags\" in some places and \"elements\" in others.\n\n\n**Security fixes**\n\nNone\n\n\n**Bug fixes**\n\n* Add support for Python 3.11. (#675)\n\n* Fix API weirness in ``BleachSanitizerFilter``. (#649)\n\n We're using \"tags\" instead of \"elements\" everywhere--no more weird\n overloading of \"elements\" anymore.\n\n Also, it no longer calls the superclass constructor.\n\n* Add warning when ``css_sanitizer`` isn't set, but the ``style``\n attribute is allowed. (#676)\n\n* Fix linkify handling of character entities. (#501)\n\n* Rework dev dependencies to use ``requirements-dev.txt`` and\n ``requirements-flake8.txt`` instead of extras.\n\n* Fix project infrastructure to be tox-based so it's easier to have CI\n run the same things we're running in development and with flake8\n in an isolated environment.\n\n* Update action versions in CI.\n\n* Switch to f-strings where possible. Make tests parametrized to be\n easier to read/maintain.\n\n\nVersion 5.0.1 (June 27th, 2022)\n-------------------------------\n\n**Security fixes**\n\nNone\n\n\n**Bug fixes**\n\n* Add missing comma to tinycss2 require. Thank you, @shadchin!\n\n* Add url parse tests based on wpt url tests. (#688)\n\n* Support scheme-less urls if \"https\" is in allow list. (#662)\n\n* Handle escaping ``<`` in edge cases where it doesn't start a tag. (#544)\n\n* Fix reference warnings in docs. (#660)\n\n* Correctly urlencode email address parts. Thank you, @larseggert! (#659)\n\n\nVersion 5.0.0 (April 7th, 2022)\n-------------------------------\n\n**Backwards incompatible changes**\n\n* ``clean`` and ``linkify`` now preserve the order of HTML attributes. Thank\n you, @askoretskly! (#566)\n\n* Drop support for Python 3.6. Thank you, @hugovk! (#629)\n\n* CSS sanitization in style tags is completely different now. If you're using\n Bleach ``clean`` to sanitize css in style tags, you'll need to update your\n code and you'll need to install the ``css`` extras::\n\n pip install 'bleach[css]'\n\n See `the documentation on sanitizing CSS for how to do it\n `_. (#633)\n\n**Security fixes**\n\nNone\n\n**Bug fixes**\n\n* Rework dev dependencies. We no longer have\n ``requirements-dev.in``/``requirements-dev.txt``. Instead, we're using\n ``dev`` extras.\n\n See `development docs `_\n for more details. (#620)\n\n* Add newline when dropping block-level tags. Thank you, @jvanasco! (#369)\n\n\nVersion 4.1.0 (August 25th, 2021)\n---------------------------------\n\n**Features**\n\n* Python 3.9 support\n\n**Security fixes**\n\nNone\n\n**Bug fixes**\n\n* Update sanitizer clean to use vendored 3.6.14 stdlib urllib.parse to\n fix test failures on Python 3.9. (#536)\n\n\nVersion 4.0.0 (August 3rd, 2021)\n--------------------------------\n\n**Backwards incompatible changes**\n\n* Drop support for unsupported Python versions <3.6. (#520)\n\n**Security fixes**\n\nNone\n\n**Features**\n\n* fix attribute name in the linkify docs (thanks @CheesyFeet!)\n\n\nVersion 3.3.1 (July 14th, 2021)\n-------------------------------\n\n**Security fixes**\n\nNone\n\n**Features**\n\n* add more tests for CVE-2021-23980 / GHSA-vv2x-vrpj-qqpq\n* bump python version to 3.8 for tox doc, vendorverify, and lint targets\n* update bug report template tag\n* update vendorverify script to detect and fail when extra files are vendored\n* update release process docs to check vendorverify passes locally\n\n**Bug fixes**\n\n* remove extra vendored django present in the v3.3.0 whl (#595)\n* duplicate h1 header doc fix (thanks Nguyễn Gia Phong / @McSinyx!)\n\n\nVersion 3.3.0 (February 1st, 2021)\n----------------------------------\n\n**Backwards incompatible changes**\n\n* clean escapes HTML comments even when strip_comments=False\n\n**Security fixes**\n\n* Fix bug 1621692 / GHSA-m6xf-fq7q-8743. See the advisory for details.\n\n**Features**\n\nNone\n\n**Bug fixes**\n\nNone\n\n\nVersion 3.2.3 (January 26th, 2021)\n----------------------------------\n\n**Security fixes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* fix clean and linkify raising ValueErrors for certain inputs. Thank you @Google-Autofuzz.\n\n\nVersion 3.2.2 (January 20th, 2021)\n----------------------------------\n\n**Security fixes**\n\nNone\n\n**Features**\n\n* Migrate CI to Github Actions. Thank you @hugovk.\n\n**Bug fixes**\n\n* fix linkify raising an IndexError on certain inputs. Thank you @Google-Autofuzz.\n\n\nVersion 3.2.1 (September 18th, 2020)\n------------------------------------\n\n**Security fixes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* change linkifier to add rel=\"nofollow\" as documented. Thank you @mitar.\n* suppress html5lib sanitizer DeprecationWarnings (#557)\n\n\nVersion 3.2.0 (September 16th, 2020)\n------------------------------------\n\n**Security fixes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* ``html5lib`` dependency to version 1.1.0. Thank you Sam Sneddon.\n* update tests_website terminology. Thank you Thomas Grainger.\n\n\nVersion 3.1.5 (April 29th, 2020)\n--------------------------------\n\n**Security fixes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* replace missing ``setuptools`` dependency with ``packaging``. Thank you Benjamin Peterson.\n\n\nVersion 3.1.4 (March 24th, 2020)\n--------------------------------\n\n**Security fixes**\n\n* ``bleach.clean`` behavior parsing style attributes could result in a\n regular expression denial of service (ReDoS).\n\n Calls to ``bleach.clean`` with an allowed tag with an allowed\n ``style`` attribute were vulnerable to ReDoS. For example,\n ``bleach.clean(..., attributes={'a': ['style']})``.\n\n This issue was confirmed in Bleach versions v3.1.3, v3.1.2, v3.1.1,\n v3.1.0, v3.0.0, v2.1.4, and v2.1.3. Earlier versions used a similar\n regular expression and should be considered vulnerable too.\n\n Anyone using Bleach <=v3.1.3 is encouraged to upgrade.\n\n https://bugzilla.mozilla.org/show_bug.cgi?id=1623633\n\n**Backwards incompatible changes**\n\n* Style attributes with dashes, or single or double quoted values are\n cleaned instead of passed through.\n\n**Features**\n\nNone\n\n**Bug fixes**\n\nNone\n\n\nVersion 3.1.3 (March 17th, 2020)\n--------------------------------\n\n**Security fixes**\n\nNone\n\n**Backwards incompatible changes**\n\n* Drop support for Python 3.4. Thank you, @hugovk!\n\n* Drop deprecated ``setup.py test`` support. Thank you, @jdufresne! (#507)\n\n**Features**\n\n* Add support for Python 3.8. Thank you, @jdufresne!\n\n* Add support for PyPy 7. Thank you, @hugovk!\n\n* Add pypy3 testing to tox and travis. Thank you, @jdufresne!\n\n**Bug fixes**\n\n* Add relative link to code of conduct. (#442)\n\n* Fix typo: curren -> current in tests/test_clean.py Thank you, timgates42! (#504)\n\n* Fix handling of non-ascii style attributes. Thank you, @sekineh! (#426)\n\n* Simplify tox configuration. Thank you, @jdufresne!\n\n* Make documentation reproducible. Thank you, @lamby!\n\n* Fix typos in code comments. Thank you, @zborboa-g!\n\n* Fix exception value testing. Thank you, @mastizada!\n\n* Fix parser-tags NoneType exception. Thank you, @bope!\n\n* Improve TLD support in linkify. Thank you, @pc-coholic!\n\n\nVersion 3.1.2 (March 11th, 2020)\n--------------------------------\n\n**Security fixes**\n\n* ``bleach.clean`` behavior parsing embedded MathML and SVG content\n with RCDATA tags did not match browser behavior and could result in\n a mutation XSS.\n\n Calls to ``bleach.clean`` with ``strip=False`` and ``math`` or\n ``svg`` tags and one or more of the RCDATA tags ``script``,\n ``noscript``, ``style``, ``noframes``, ``iframe``, ``noembed``, or\n ``xmp`` in the allowed tags whitelist were vulnerable to a mutation\n XSS.\n\n This security issue was confirmed in Bleach version v3.1.1. Earlier\n versions are likely affected too.\n\n Anyone using Bleach <=v3.1.1 is encouraged to upgrade.\n\n https://bugzilla.mozilla.org/show_bug.cgi?id=1621692\n\n**Backwards incompatible changes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\nNone\n\n\nVersion 3.1.1 (February 13th, 2020)\n-----------------------------------\n\n**Security fixes**\n\n* ``bleach.clean`` behavior parsing ``noscript`` tags did not match\n browser behavior.\n\n Calls to ``bleach.clean`` allowing ``noscript`` and one or more of\n the raw text tags (``title``, ``textarea``, ``script``, ``style``,\n ``noembed``, ``noframes``, ``iframe``, and ``xmp``) were vulnerable\n to a mutation XSS.\n\n This security issue was confirmed in Bleach versions v2.1.4, v3.0.2,\n and v3.1.0. Earlier versions are probably affected too.\n\n Anyone using Bleach <=v3.1.0 is highly encouraged to upgrade.\n\n https://bugzilla.mozilla.org/show_bug.cgi?id=1615315\n\n**Backwards incompatible changes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\nNone\n\n\nVersion 3.1.0 (January 9th, 2019)\n---------------------------------\n\n**Security fixes**\n\nNone\n\n**Backwards incompatible changes**\n\nNone\n\n**Features**\n\n* Add ``recognized_tags`` argument to the linkify ``Linker`` class. This\n fixes issues when linkifying on its own and having some tags get escaped.\n It defaults to a list of HTML5 tags. Thank you, Chad Birch! (#409)\n\n**Bug fixes**\n\n* Add ``six>=1.9`` to requirements. Thank you, Dave Shawley (#416)\n\n* Fix cases where attribute names could have invalid characters in them.\n (#419)\n\n* Fix problems with ``LinkifyFilter`` not being able to match links\n across ``&``. (#422)\n\n* Fix ``InputStreamWithMemory`` when the ``BleachHTMLParser`` is\n parsing ``meta`` tags. (#431)\n\n* Fix doctests. (#357)\n\n\nVersion 3.0.2 (October 11th, 2018)\n----------------------------------\n\n**Security fixes**\n\nNone\n\n**Backwards incompatible changes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* Merge ``Characters`` tokens after sanitizing them. This fixes issues in the\n ``LinkifyFilter`` where it was only linkifying parts of urls. (#374)\n\n\nVersion 3.0.1 (October 9th, 2018)\n---------------------------------\n\n**Security fixes**\n\nNone\n\n**Backwards incompatible changes**\n\nNone\n\n**Features**\n\n* Support Python 3.7. It supported Python 3.7 just fine, but we added 3.7 to\n the list of Python environments we test so this is now officially supported.\n (#377)\n\n**Bug fixes**\n\n* Fix ``list`` object has no attribute ``lower`` in ``clean``. (#398)\n* Fix ``abbr`` getting escaped in ``linkify``. (#400)\n\n\nVersion 3.0.0 (October 3rd, 2018)\n---------------------------------\n\n**Security fixes**\n\nNone\n\n**Backwards incompatible changes**\n\n* A bunch of functions were moved from one module to another.\n\n These were moved from ``bleach.sanitizer`` to ``bleach.html5lib_shim``:\n\n * ``convert_entity``\n * ``convert_entities``\n * ``match_entity``\n * ``next_possible_entity``\n * ``BleachHTMLSerializer``\n * ``BleachHTMLTokenizer``\n * ``BleachHTMLParser``\n\n These functions and classes weren't documented and aren't part of the\n public API, but people read code and might be using them so we're\n considering it an incompatible API change.\n\n If you're using them, you'll need to update your code.\n\n**Features**\n\n* Bleach no longer depends on html5lib. html5lib==1.0.1 is now vendored into\n Bleach. You can remove it from your requirements file if none of your other\n requirements require html5lib.\n\n This means Bleach will now work fine with other libraries that depend on\n html5lib regardless of what version of html5lib they require. (#386)\n\n**Bug fixes**\n\n* Fixed tags getting added when using clean or linkify. This was a\n long-standing regression from the Bleach 2.0 rewrite. (#280, #392)\n\n* Fixed ```` getting replaced with a string. Now it gets escaped or\n stripped depending on whether it's in the allowed tags or not. (#279)\n\n\nVersion 2.1.4 (August 16th, 2018)\n---------------------------------\n\n**Security fixes**\n\nNone\n\n**Backwards incompatible changes**\n\n* Dropped support for Python 3.3. (#328)\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* Handle ambiguous ampersands in correctly. (#359)\n\n\nVersion 2.1.3 (March 5th, 2018)\n-------------------------------\n\n**Security fixes**\n\n* Attributes that have URI values weren't properly sanitized if the\n values contained character entities. Using character entities, it\n was possible to construct a URI value with a scheme that was not\n allowed that would slide through unsanitized.\n\n This security issue was introduced in Bleach 2.1. Anyone using\n Bleach 2.1 is highly encouraged to upgrade.\n\n https://bugzilla.mozilla.org/show_bug.cgi?id=1442745\n\n**Backwards incompatible changes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* Fixed some other edge cases for attribute URI value sanitizing and\n improved testing of this code.\n\n\nVersion 2.1.2 (December 7th, 2017)\n----------------------------------\n\n**Security fixes**\n\nNone\n\n**Backwards incompatible changes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* Support html5lib-python 1.0.1. (#337)\n\n* Add deprecation warning for supporting html5lib-python < 1.0.\n\n* Switch to semver.\n\n\nVersion 2.1.1 (October 2nd, 2017)\n---------------------------------\n\n**Security fixes**\n\nNone\n\n**Backwards incompatible changes**\n\nNone\n\n**Features**\n\nNone\n\n**Bug fixes**\n\n* Fix ``setup.py`` opening files when ``LANG=``. (#324)\n\n\nVersion 2.1 (September 28th, 2017)\n----------------------------------\n\n**Security fixes**\n\n* Convert control characters (backspace particularly) to \"?\" preventing\n malicious copy-and-paste situations. (#298)\n\n See ``_ for more details.\n\n This affects all previous versions of Bleach. Check the comments on that\n issue for ways to alleviate the issue if you can't upgrade to Bleach 2.1.\n\n\n**Backwards incompatible changes**\n\n* Redid versioning. ``bleach.VERSION`` is no longer available. Use the string\n version at ``bleach.__version__`` and parse it with\n ``pkg_resources.parse_version``. (#307)\n\n* clean, linkify: linkify and clean should only accept text types; thank you,\n Janusz! (#292)\n\n* clean, linkify: accept only unicode or utf-8-encoded str (#176)\n\n\n**Features**\n\n\n**Bug fixes**\n\n* ``bleach.clean()`` no longer unescapes entities including ones that are missing\n a ``;`` at the end which can happen in urls and other places. (#143)\n\n* linkify: fix http links inside of mailto links; thank you, sedrubal! (#300)\n\n* clarify security policy in docs (#303)\n\n* fix dependency specification for html5lib 1.0b8, 1.0b9, and 1.0b10; thank you,\n Zoltán! (#268)\n\n* add Bleach vs. html5lib comparison to README; thank you, Stu Cox! (#278)\n\n* fix KeyError exceptions on tags without href attr; thank you, Alex Defsen!\n (#273)\n\n* add test website and scripts to test ``bleach.clean()`` output in browser;\n thank you, Greg Guthe!\n\n\nVersion 2.0 (March 8th, 2017)\n-----------------------------\n\n**Security fixes**\n\n* None\n\n\n**Backwards incompatible changes**\n\n* Removed support for Python 2.6. (#206)\n\n* Removed support for Python 3.2. (#224)\n\n* Bleach no longer supports html5lib < 0.99999999 (8 9s).\n\n This version is a rewrite to use the new sanitizing API since the old\n one was dropped in html5lib 0.99999999 (8 9s).\n\n If you're using 0.9999999 (7 9s) upgrade to 0.99999999 (8 9s) or higher.\n\n If you're using 1.0b8 (equivalent to 0.9999999 (7 9s)), upgrade to 1.0b9\n (equivalent to 0.99999999 (8 9s)) or higher.\n\n* ``bleach.clean`` and friends were rewritten\n\n ``clean`` was reimplemented as an html5lib filter and happens at a different\n step in the HTML parsing -> traversing -> serializing process. Because of\n that, there are some differences in clean's output as compared with previous\n versions.\n\n Amongst other things, this version will add end tags even if the tag in\n question is to be escaped.\n\n* ``bleach.clean`` and friends attribute callables now take three arguments:\n tag, attribute name and attribute value. Previously they only took attribute\n name and attribute value.\n\n All attribute callables will need to be updated.\n\n* ``bleach.linkify`` was rewritten\n\n ``linkify`` was reimplemented as an html5lib Filter. As such, it no longer\n accepts a ``tokenizer`` argument.\n\n The callback functions for adjusting link attributes now takes a namespaced\n attribute.\n\n Previously you'd do something like this::\n\n def check_protocol(attrs, is_new):\n if not attrs.get('href', '').startswith('http:', 'https:')):\n return None\n return attrs\n\n Now it's more like this::\n\n def check_protocol(attrs, is_new):\n if not attrs.get((None, u'href'), u'').startswith(('http:', 'https:')):\n # ^^^^^^^^^^^^^^^\n return None\n return attrs\n\n Further, you need to make sure you're always using unicode values. If you\n don't then html5lib will raise an assertion error that the value is not\n unicode.\n\n All linkify filters will need to be updated.\n\n* ``bleach.linkify`` and friends had a ``skip_pre`` argument--that's been\n replaced with a more general ``skip_tags`` argument.\n\n Before, you might do::\n\n bleach.linkify(some_text, skip_pre=True)\n\n The equivalent with Bleach 2.0 is::\n\n bleach.linkify(some_text, skip_tags=['pre'])\n\n You can skip other tags, too, like ``style`` or ``script`` or other places\n where you don't want linkification happening.\n\n All uses of linkify that use ``skip_pre`` will need to be updated.\n\n\n**Changes**\n\n* Supports Python 3.6.\n\n* Supports html5lib >= 0.99999999 (8 9s).\n\n* There's a ``bleach.sanitizer.Cleaner`` class that you can instantiate with your\n favorite clean settings for easy reuse.\n\n* There's a ``bleach.linkifier.Linker`` class that you can instantiate with your\n favorite linkify settings for easy reuse.\n\n* There's a ``bleach.linkifier.LinkifyFilter`` which is an htm5lib filter that\n you can pass as a filter to ``bleach.sanitizer.Cleaner`` allowing you to clean\n and linkify in one pass.\n\n* ``bleach.clean`` and friends can now take a callable as an attributes arg value.\n\n* Tons of bug fixes.\n\n* Cleaned up tests.\n\n* Documentation fixes.\n\n\nVersion 1.5 (November 4th, 2016)\n--------------------------------\n\n**Security fixes**\n\n* None\n\n**Backwards incompatible changes**\n\n* clean: The list of ``ALLOWED_PROTOCOLS`` now defaults to http, https and\n mailto.\n\n Previously it was a long list of protocols something like ed2k, ftp, http,\n https, irc, mailto, news, gopher, nntp, telnet, webcal, xmpp, callto, feed,\n urn, aim, rsync, tag, ssh, sftp, rtsp, afs, data. (#149)\n\n**Changes**\n\n* clean: Added ``protocols`` to arguments list to let you override the list of\n allowed protocols. Thank you, Andreas Malecki! (#149)\n\n* linkify: Fix a bug involving periods at the end of an email address. Thank you,\n Lorenz Schori! (#219)\n\n* linkify: Fix linkification of non-ascii ports. Thank you Alexandre, Macabies!\n (#207)\n\n* linkify: Fix linkify inappropriately removing node tails when dropping nodes.\n (#132)\n\n* Fixed a test that failed periodically. (#161)\n\n* Switched from nose to py.test. (#204)\n\n* Add test matrix for all supported Python and html5lib versions. (#230)\n\n* Limit to html5lib ``>=0.999,!=0.9999,!=0.99999,<0.99999999`` because 0.9999\n and 0.99999 are busted.\n\n* Add support for ``python setup.py test``. (#97)\n\n\nVersion 1.4.3 (May 23rd, 2016)\n------------------------------\n\n**Security fixes**\n\n* None\n\n**Changes**\n\n* Limit to html5lib ``>=0.999,<0.99999999`` because of impending change to\n sanitizer api. #195\n\n\nVersion 1.4.2 (September 11, 2015)\n----------------------------------\n\n**Changes**\n\n* linkify: Fix hang in linkify with ``parse_email=True``. (#124)\n\n* linkify: Fix crash in linkify when removing a link that is a first-child. (#136)\n\n* Updated TLDs.\n\n* linkify: Don't remove exterior brackets when linkifying. (#146)\n\n\nVersion 1.4.1 (December 15, 2014)\n---------------------------------\n\n**Changes**\n\n* Consistent order of attributes in output.\n\n* Python 3.4 support.\n\n\nVersion 1.4 (January 12, 2014)\n------------------------------\n\n**Changes**\n\n* linkify: Update linkify to use etree type Treewalker instead of simpletree.\n\n* Updated html5lib to version ``>=0.999``.\n\n* Update all code to be compatible with Python 3 and 2 using six.\n\n* Switch to Apache License.\n\n\nVersion 1.3\n-----------\n\n* Used by Python 3-only fork.\n\n\nVersion 1.2.2 (May 18, 2013)\n----------------------------\n\n* Pin html5lib to version 0.95 for now due to major API break.\n\n\nVersion 1.2.1 (February 19, 2013)\n---------------------------------\n\n* ``clean()`` no longer considers ``feed:`` an acceptable protocol due to\n inconsistencies in browser behavior.\n\n\nVersion 1.2 (January 28, 2013)\n------------------------------\n\n* ``linkify()`` has changed considerably. Many keyword arguments have been\n replaced with a single callbacks list. Please see the documentation for more\n information.\n\n* Bleach will no longer consider unacceptable protocols when linkifying.\n\n* ``linkify()`` now takes a tokenizer argument that allows it to skip\n sanitization.\n\n* ``delinkify()`` is gone.\n\n* Removed exception handling from ``_render``. ``clean()`` and ``linkify()`` may\n now throw.\n\n* ``linkify()`` correctly ignores case for protocols and domain names.\n\n* ``linkify()`` correctly handles markup within an tag.\n\n\nVersion 1.1.5\n-------------\n\n\nVersion 1.1.4\n-------------\n\n\nVersion 1.1.3 (July 10, 2012)\n-----------------------------\n\n* Fix parsing bare URLs when parse_email=True.\n\n\nVersion 1.1.2 (June 1, 2012)\n----------------------------\n\n* Fix hang in style attribute sanitizer. (#61)\n\n* Allow ``/`` in style attribute values.\n\n\nVersion 1.1.1 (February 17, 2012)\n---------------------------------\n\n* Fix tokenizer for html5lib 0.9.5.\n\n\nVersion 1.1.0 (October 24, 2011)\n--------------------------------\n\n* ``linkify()`` now understands port numbers. (#38)\n\n* Documented character encoding behavior. (#41)\n\n* Add an optional target argument to ``linkify()``.\n\n* Add ``delinkify()`` method. (#45)\n\n* Support subdomain whitelist for ``delinkify()``. (#47, #48)\n\n\nVersion 1.0.4 (September 2, 2011)\n---------------------------------\n\n* Switch to SemVer git tags.\n\n* Make ``linkify()`` smarter about trailing punctuation. (#30)\n\n* Pass ``exc_info`` to logger during rendering issues.\n\n* Add wildcard key for attributes. (#19)\n\n* Make ``linkify()`` use the ``HTMLSanitizer`` tokenizer. (#36)\n\n* Fix URLs wrapped in parentheses. (#23)\n\n* Make ``linkify()`` UTF-8 safe. (#33)\n\n\nVersion 1.0.3 (June 14, 2011)\n-----------------------------\n\n* ``linkify()`` works with 3rd level domains. (#24)\n\n* ``clean()`` supports vendor prefixes in style values. (#31, #32)\n\n* Fix ``linkify()`` email escaping.\n\n\nVersion 1.0.2 (June 6, 2011)\n----------------------------\n\n* ``linkify()`` supports email addresses.\n\n* ``clean()`` supports callables in attributes filter.\n\n\nVersion 1.0.1 (April 12, 2011)\n------------------------------\n\n* ``linkify()`` doesn't drop trailing slashes. (#21)\n* ``linkify()`` won't linkify 'libgl.so.1'. (#22)\n", + "description_content_type": "text/x-rst", + "home_page": "https://github.com/mozilla/bleach", + "maintainer": "Will Kahn-Greene", + "maintainer_email": "willkg@mozilla.com", + "license": "Apache Software License", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development :: Libraries :: Python Modules" + ], + "requires_dist": [ + "six >=1.9.0", + "webencodings", + "tinycss2 <1.3,>=1.1.0 ; extra == 'css'" + ], + "requires_python": ">=3.8", + "provides_extra": [ + "css" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", + "archive_info": { + "hash": "sha256=96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", + "hashes": { + "sha256": "96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "charset-normalizer", + "version": "3.3.2", + "summary": "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet.", + "description": "

Charset Detection, for Everyone 👋

\r\n\r\n

\r\n The Real First Universal Charset Detector
\r\n
\r\n \r\n \r\n \r\n \"Download\r\n \r\n \r\n \r\n \r\n

\r\n

\r\n Featured Packages
\r\n \r\n \"Static\r\n \r\n \r\n \"Static\r\n \r\n

\r\n

\r\n In other language (unofficial port - by the community)
\r\n \r\n \"Static\r\n \r\n

\r\n\r\n> A library that helps you read text from an unknown charset encoding.
Motivated by `chardet`,\r\n> I'm trying to resolve the issue by taking a new approach.\r\n> All IANA character set names for which the Python core library provides codecs are supported.\r\n\r\n

\r\n >>>>> 👉 Try Me Online Now, Then Adopt Me 👈 <<<<<\r\n

\r\n\r\nThis project offers you an alternative to **Universal Charset Encoding Detector**, also known as **Chardet**.\r\n\r\n| Feature | [Chardet](https://github.com/chardet/chardet) | Charset Normalizer | [cChardet](https://github.com/PyYoshi/cChardet) |\r\n|--------------------------------------------------|:---------------------------------------------:|:--------------------------------------------------------------------------------------------------:|:-----------------------------------------------:|\r\n| `Fast` | ❌ | ✅ | ✅ |\r\n| `Universal**` | ❌ | ✅ | ❌ |\r\n| `Reliable` **without** distinguishable standards | ❌ | ✅ | ✅ |\r\n| `Reliable` **with** distinguishable standards | ✅ | ✅ | ✅ |\r\n| `License` | LGPL-2.1
_restrictive_ | MIT | MPL-1.1
_restrictive_ |\r\n| `Native Python` | ✅ | ✅ | ❌ |\r\n| `Detect spoken language` | ❌ | ✅ | N/A |\r\n| `UnicodeDecodeError Safety` | ❌ | ✅ | ❌ |\r\n| `Whl Size (min)` | 193.6 kB | 42 kB | ~200 kB |\r\n| `Supported Encoding` | 33 | 🎉 [99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings) | 40 |\r\n\r\n

\r\n\"Reading\"Cat\r\n

\r\n\r\n*\\*\\* : They are clearly using specific code for a specific encoding even if covering most of used one*
\r\nDid you got there because of the logs? See [https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html](https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html)\r\n\r\n## ⚡ Performance\r\n\r\nThis package offer better performance than its counterpart Chardet. Here are some numbers.\r\n\r\n| Package | Accuracy | Mean per file (ms) | File per sec (est) |\r\n|-----------------------------------------------|:--------:|:------------------:|:------------------:|\r\n| [chardet](https://github.com/chardet/chardet) | 86 % | 200 ms | 5 file/sec |\r\n| charset-normalizer | **98 %** | **10 ms** | 100 file/sec |\r\n\r\n| Package | 99th percentile | 95th percentile | 50th percentile |\r\n|-----------------------------------------------|:---------------:|:---------------:|:---------------:|\r\n| [chardet](https://github.com/chardet/chardet) | 1200 ms | 287 ms | 23 ms |\r\n| charset-normalizer | 100 ms | 50 ms | 5 ms |\r\n\r\nChardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload.\r\n\r\n> Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows.\r\n> And yes, these results might change at any time. The dataset can be updated to include more files.\r\n> The actual delays heavily depends on your CPU capabilities. The factors should remain the same.\r\n> Keep in mind that the stats are generous and that Chardet accuracy vs our is measured using Chardet initial capability\r\n> (eg. Supported Encoding) Challenge-them if you want.\r\n\r\n## ✨ Installation\r\n\r\nUsing pip:\r\n\r\n```sh\r\npip install charset-normalizer -U\r\n```\r\n\r\n## 🚀 Basic Usage\r\n\r\n### CLI\r\nThis package comes with a CLI.\r\n\r\n```\r\nusage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD]\r\n file [file ...]\r\n\r\nThe Real First Universal Charset Detector. Discover originating encoding used\r\non text file. Normalize text to unicode.\r\n\r\npositional arguments:\r\n files File(s) to be analysed\r\n\r\noptional arguments:\r\n -h, --help show this help message and exit\r\n -v, --verbose Display complementary information about file if any.\r\n Stdout will contain logs about the detection process.\r\n -a, --with-alternative\r\n Output complementary possibilities if any. Top-level\r\n JSON WILL be a list.\r\n -n, --normalize Permit to normalize input file. If not set, program\r\n does not write anything.\r\n -m, --minimal Only output the charset detected to STDOUT. Disabling\r\n JSON output.\r\n -r, --replace Replace file when trying to normalize it instead of\r\n creating a new one.\r\n -f, --force Replace file without asking if you are sure, use this\r\n flag with caution.\r\n -t THRESHOLD, --threshold THRESHOLD\r\n Define a custom maximum amount of chaos allowed in\r\n decoded content. 0. <= chaos <= 1.\r\n --version Show version information and exit.\r\n```\r\n\r\n```bash\r\nnormalizer ./data/sample.1.fr.srt\r\n```\r\n\r\nor\r\n\r\n```bash\r\npython -m charset_normalizer ./data/sample.1.fr.srt\r\n```\r\n\r\n🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format.\r\n\r\n```json\r\n{\r\n \"path\": \"/home/default/projects/charset_normalizer/data/sample.1.fr.srt\",\r\n \"encoding\": \"cp1252\",\r\n \"encoding_aliases\": [\r\n \"1252\",\r\n \"windows_1252\"\r\n ],\r\n \"alternative_encodings\": [\r\n \"cp1254\",\r\n \"cp1256\",\r\n \"cp1258\",\r\n \"iso8859_14\",\r\n \"iso8859_15\",\r\n \"iso8859_16\",\r\n \"iso8859_3\",\r\n \"iso8859_9\",\r\n \"latin_1\",\r\n \"mbcs\"\r\n ],\r\n \"language\": \"French\",\r\n \"alphabets\": [\r\n \"Basic Latin\",\r\n \"Latin-1 Supplement\"\r\n ],\r\n \"has_sig_or_bom\": false,\r\n \"chaos\": 0.149,\r\n \"coherence\": 97.152,\r\n \"unicode_path\": null,\r\n \"is_preferred\": true\r\n}\r\n```\r\n\r\n### Python\r\n*Just print out normalized text*\r\n```python\r\nfrom charset_normalizer import from_path\r\n\r\nresults = from_path('./my_subtitle.srt')\r\n\r\nprint(str(results.best()))\r\n```\r\n\r\n*Upgrade your code without effort*\r\n```python\r\nfrom charset_normalizer import detect\r\n```\r\n\r\nThe above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible.\r\n\r\nSee the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/)\r\n\r\n## 😇 Why\r\n\r\nWhen I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a\r\nreliable alternative using a completely different method. Also! I never back down on a good challenge!\r\n\r\nI **don't care** about the **originating charset** encoding, because **two different tables** can\r\nproduce **two identical rendered string.**\r\nWhat I want is to get readable text, the best I can. \r\n\r\nIn a way, **I'm brute forcing text decoding.** How cool is that ? 😎\r\n\r\nDon't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode.\r\n\r\n## 🍰 How\r\n\r\n - Discard all charset encoding table that could not fit the binary content.\r\n - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding.\r\n - Extract matches with the lowest mess detected.\r\n - Additionally, we measure coherence / probe for a language.\r\n\r\n**Wait a minute**, what is noise/mess and coherence according to **YOU ?**\r\n\r\n*Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then\r\n**I established** some ground rules about **what is obvious** when **it seems like** a mess.\r\n I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to\r\n improve or rewrite it.\r\n\r\n*Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought\r\nthat intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design.\r\n\r\n## ⚡ Known limitations\r\n\r\n - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters))\r\n - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content.\r\n\r\n## ⚠️ About Python EOLs\r\n\r\n**If you are running:**\r\n\r\n- Python >=2.7,<3.5: Unsupported\r\n- Python 3.5: charset-normalizer < 2.1\r\n- Python 3.6: charset-normalizer < 3.1\r\n- Python 3.7: charset-normalizer < 4.0\r\n\r\nUpgrade your Python interpreter as soon as possible.\r\n\r\n## 👤 Contributing\r\n\r\nContributions, issues and feature requests are very much welcome.
\r\nFeel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute.\r\n\r\n## 📝 License\r\n\r\nCopyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).
\r\nThis project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed.\r\n\r\nCharacters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/)\r\n\r\n## 💼 For Enterprise\r\n\r\nProfessional support for charset-normalizer is available as part of the [Tidelift\r\nSubscription][1]. Tidelift gives software development teams a single source for\r\npurchasing and maintaining their software, with professional grade assurances\r\nfrom the experts who know it best, while seamlessly integrating with existing\r\ntools.\r\n\r\n[1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme\r\n\r\n# Changelog\r\nAll notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\r\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).\r\n\r\n## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31)\r\n\r\n### Fixed\r\n- Unintentional memory usage regression when using large payload that match several encoding (#376)\r\n- Regression on some detection case showcased in the documentation (#371)\r\n\r\n### Added\r\n- Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife)\r\n\r\n## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22)\r\n\r\n### Changed\r\n- Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8\r\n- Improved the general detection reliability based on reports from the community\r\n\r\n## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30)\r\n\r\n### Added\r\n- Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer`\r\n- Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323)\r\n\r\n### Removed\r\n- (internal) Redundant utils.is_ascii function and unused function is_private_use_only\r\n- (internal) charset_normalizer.assets is moved inside charset_normalizer.constant\r\n\r\n### Changed\r\n- (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection\r\n- Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8\r\n\r\n### Fixed\r\n- Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \\_\\_lt\\_\\_ (#350)\r\n\r\n## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07)\r\n\r\n### Changed\r\n- Typehint for function `from_path` no longer enforce `PathLike` as its first argument\r\n- Minor improvement over the global detection reliability\r\n\r\n### Added\r\n- Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries\r\n- Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True)\r\n- Explicit support for Python 3.12\r\n\r\n### Fixed\r\n- Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289)\r\n\r\n## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06)\r\n\r\n### Added\r\n- Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262)\r\n\r\n### Removed\r\n- Support for Python 3.6 (PR #260)\r\n\r\n### Changed\r\n- Optional speedup provided by mypy/c 1.0.1\r\n\r\n## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18)\r\n\r\n### Fixed\r\n- Multi-bytes cutter/chunk generator did not always cut correctly (PR #233)\r\n\r\n### Changed\r\n- Speedup provided by mypy/c 0.990 on Python >= 3.7\r\n\r\n## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20)\r\n\r\n### Added\r\n- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results\r\n- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES\r\n- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio\r\n- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl)\r\n\r\n### Changed\r\n- Build with static metadata using 'build' frontend\r\n- Make the language detection stricter\r\n- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1\r\n\r\n### Fixed\r\n- CLI with opt --normalize fail when using full path for files\r\n- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it\r\n- Sphinx warnings when generating the documentation\r\n\r\n### Removed\r\n- Coherence detector no longer return 'Simple English' instead return 'English'\r\n- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese'\r\n- Breaking: Method `first()` and `best()` from CharsetMatch\r\n- UTF-7 will no longer appear as \"detected\" without a recognized SIG/mark (is unreliable/conflict with ASCII)\r\n- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches\r\n- Breaking: Top-level function `normalize`\r\n- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch\r\n- Support for the backport `unicodedata2`\r\n\r\n## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18)\r\n\r\n### Added\r\n- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results\r\n- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES\r\n- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio\r\n\r\n### Changed\r\n- Build with static metadata using 'build' frontend\r\n- Make the language detection stricter\r\n\r\n### Fixed\r\n- CLI with opt --normalize fail when using full path for files\r\n- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it\r\n\r\n### Removed\r\n- Coherence detector no longer return 'Simple English' instead return 'English'\r\n- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese'\r\n\r\n## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21)\r\n\r\n### Added\r\n- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl)\r\n\r\n### Removed\r\n- Breaking: Method `first()` and `best()` from CharsetMatch\r\n- UTF-7 will no longer appear as \"detected\" without a recognized SIG/mark (is unreliable/conflict with ASCII)\r\n\r\n### Fixed\r\n- Sphinx warnings when generating the documentation\r\n\r\n## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15)\r\n\r\n### Changed\r\n- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1\r\n\r\n### Removed\r\n- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches\r\n- Breaking: Top-level function `normalize`\r\n- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch\r\n- Support for the backport `unicodedata2`\r\n\r\n## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19)\r\n\r\n### Deprecated\r\n- Function `normalize` scheduled for removal in 3.0\r\n\r\n### Changed\r\n- Removed useless call to decode in fn is_unprintable (#206)\r\n\r\n### Fixed\r\n- Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204)\r\n\r\n## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19)\r\n\r\n### Added\r\n- Output the Unicode table version when running the CLI with `--version` (PR #194)\r\n\r\n### Changed\r\n- Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175)\r\n- Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183)\r\n\r\n### Fixed\r\n- Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175)\r\n- CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181)\r\n\r\n### Removed\r\n- Support for Python 3.5 (PR #192)\r\n\r\n### Deprecated\r\n- Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194)\r\n\r\n## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12)\r\n\r\n### Fixed\r\n- ASCII miss-detection on rare cases (PR #170) \r\n\r\n## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30)\r\n\r\n### Added\r\n- Explicit support for Python 3.11 (PR #164)\r\n\r\n### Changed\r\n- The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165)\r\n\r\n## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04)\r\n\r\n### Fixed\r\n- Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154)\r\n\r\n### Changed\r\n- Skipping the language-detection (CD) on ASCII (PR #155)\r\n\r\n## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03)\r\n\r\n### Changed\r\n- Moderating the logging impact (since 2.0.8) for specific environments (PR #147)\r\n\r\n### Fixed\r\n- Wrong logging level applied when setting kwarg `explain` to True (PR #146)\r\n\r\n## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24)\r\n### Changed\r\n- Improvement over Vietnamese detection (PR #126)\r\n- MD improvement on trailing data and long foreign (non-pure latin) data (PR #124)\r\n- Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122)\r\n- call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129)\r\n- Code style as refactored by Sourcery-AI (PR #131) \r\n- Minor adjustment on the MD around european words (PR #133)\r\n- Remove and replace SRTs from assets / tests (PR #139)\r\n- Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135)\r\n- Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135)\r\n\r\n### Fixed\r\n- Fix large (misleading) sequence giving UnicodeDecodeError (PR #137)\r\n- Avoid using too insignificant chunk (PR #137)\r\n\r\n### Added\r\n- Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135)\r\n- Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141)\r\n\r\n## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11)\r\n### Added\r\n- Add support for Kazakh (Cyrillic) language detection (PR #109)\r\n\r\n### Changed\r\n- Further, improve inferring the language from a given single-byte code page (PR #112)\r\n- Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116)\r\n- Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113)\r\n- Various detection improvement (MD+CD) (PR #117)\r\n\r\n### Removed\r\n- Remove redundant logging entry about detected language(s) (PR #115)\r\n\r\n### Fixed\r\n- Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102)\r\n\r\n## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18)\r\n### Fixed\r\n- Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100)\r\n- Fix CLI crash when using --minimal output in certain cases (PR #103)\r\n\r\n### Changed\r\n- Minor improvement to the detection efficiency (less than 1%) (PR #106 #101)\r\n\r\n## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14)\r\n### Changed\r\n- The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81)\r\n- The BC-support with v1.x was improved, the old staticmethods are restored (PR #82)\r\n- The Unicode detection is slightly improved (PR #93)\r\n- Add syntax sugar \\_\\_bool\\_\\_ for results CharsetMatches list-container (PR #91)\r\n\r\n### Removed\r\n- The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92)\r\n\r\n### Fixed\r\n- In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95)\r\n- Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96)\r\n- The MANIFEST.in was not exhaustive (PR #78)\r\n\r\n## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30)\r\n### Fixed\r\n- The CLI no longer raise an unexpected exception when no encoding has been found (PR #70)\r\n- Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68)\r\n- The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72)\r\n- Submatch factoring could be wrong in rare edge cases (PR #72)\r\n- Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72)\r\n- Fix line endings from CRLF to LF for certain project files (PR #67)\r\n\r\n### Changed\r\n- Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76)\r\n- Allow fallback on specified encoding if any (PR #71)\r\n\r\n## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16)\r\n### Changed\r\n- Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63)\r\n- According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64)\r\n\r\n## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15)\r\n### Fixed\r\n- Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59) \r\n\r\n### Changed\r\n- Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57)\r\n\r\n## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13)\r\n### Fixed\r\n- Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55)\r\n- Using explain=False permanently disable the verbose output in the current runtime (PR #47)\r\n- One log entry (language target preemptive) was not show in logs when using explain=True (PR #47)\r\n- Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52)\r\n\r\n### Changed\r\n- Public function normalize default args values were not aligned with from_bytes (PR #53)\r\n\r\n### Added\r\n- You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47)\r\n\r\n## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02)\r\n### Changed\r\n- 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet.\r\n- Accent has been made on UTF-8 detection, should perform rather instantaneous.\r\n- The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible.\r\n- The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time)\r\n- The program has been rewritten to ease the readability and maintainability. (+Using static typing)+\r\n- utf_7 detection has been reinstated.\r\n\r\n### Removed\r\n- This package no longer require anything when used with Python 3.5 (Dropped cached_property)\r\n- Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian.\r\n- The exception hook on UnicodeDecodeError has been removed.\r\n\r\n### Deprecated\r\n- Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0\r\n\r\n### Fixed\r\n- The CLI output used the relative path of the file(s). Should be absolute.\r\n\r\n## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28)\r\n### Fixed\r\n- Logger configuration/usage no longer conflict with others (PR #44)\r\n\r\n## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21)\r\n### Removed\r\n- Using standard logging instead of using the package loguru.\r\n- Dropping nose test framework in favor of the maintained pytest.\r\n- Choose to not use dragonmapper package to help with gibberish Chinese/CJK text.\r\n- Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version.\r\n- Stop support for UTF-7 that does not contain a SIG.\r\n- Dropping PrettyTable, replaced with pure JSON output in CLI.\r\n\r\n### Fixed\r\n- BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process.\r\n- Not searching properly for the BOM when trying utf32/16 parent codec.\r\n\r\n### Changed\r\n- Improving the package final size by compressing frequencies.json.\r\n- Huge improvement over the larges payload.\r\n\r\n### Added\r\n- CLI now produces JSON consumable output.\r\n- Return ASCII if given sequences fit. Given reasonable confidence.\r\n\r\n## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13)\r\n\r\n### Fixed\r\n- In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40)\r\n\r\n## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12)\r\n\r\n### Fixed\r\n- Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39)\r\n\r\n## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12)\r\n\r\n### Fixed\r\n- The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38)\r\n\r\n## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09)\r\n\r\n### Changed\r\n- Amend the previous release to allow prettytable 2.0 (PR #35)\r\n\r\n## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08)\r\n\r\n### Fixed\r\n- Fix error while using the package with a python pre-release interpreter (PR #33)\r\n\r\n### Changed\r\n- Dependencies refactoring, constraints revised.\r\n\r\n### Added\r\n- Add python 3.9 and 3.10 to the supported interpreters\r\n\r\nMIT License\r\n\r\nCopyright (c) 2019 TAHRI Ahmed R.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n", + "description_content_type": "text/markdown", + "keywords": [ + "encoding", + "charset", + "charset-detector", + "detector", + "normalization", + "unicode", + "chardet", + "detect" + ], + "home_page": "https://github.com/Ousret/charset_normalizer", + "author": "Ahmed TAHRI", + "author_email": "ahmed.tahri@cloudnursery.dev", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: MIT License", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries :: Python Modules", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Text Processing :: Linguistic", + "Topic :: Utilities", + "Typing :: Typed" + ], + "requires_python": ">=3.7.0", + "project_url": [ + "Bug Reports, https://github.com/Ousret/charset_normalizer/issues", + "Documentation, https://charset-normalizer.readthedocs.io/en/latest" + ], + "provides_extra": [ + "unicode_backport" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/9c/b9/79691036d4a8f9857e74d1728b23f34f583b81350a27492edda58d5604e1/fastjsonschema-2.19.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0", + "hashes": { + "sha256": "3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "fastjsonschema", + "version": "2.19.1", + "summary": "Fastest Python implementation of JSON schema", + "description": "===========================\nFast JSON schema for Python\n===========================\n\n|PyPI| |Pythons|\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/fastjsonschema.svg\n :alt: PyPI version\n :target: https://pypi.python.org/pypi/fastjsonschema\n\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/fastjsonschema.svg\n :alt: Supported Python versions\n :target: https://pypi.python.org/pypi/fastjsonschema\n\nSee `documentation `_.\n", + "home_page": "https://github.com/horejsek/python-fastjsonschema", + "author": "Michal Horejsek", + "author_email": "fastjsonschema@horejsek.com", + "license": "BSD", + "classifier": [ + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries :: Python Modules" + ], + "requires_dist": [ + "colorama ; extra == 'devel'", + "jsonschema ; extra == 'devel'", + "json-spec ; extra == 'devel'", + "pylint ; extra == 'devel'", + "pytest ; extra == 'devel'", + "pytest-benchmark ; extra == 'devel'", + "pytest-cache ; extra == 'devel'", + "validictory ; extra == 'devel'" + ], + "provides_extra": [ + "devel" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", + "hashes": { + "sha256": "e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "h11", + "version": "0.14.0", + "summary": "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1", + "description": "h11\n===\n\n.. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master\n :target: https://travis-ci.org/python-hyper/h11\n :alt: Automated test status\n\n.. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/python-hyper/h11\n :alt: Test coverage\n\n.. image:: https://readthedocs.org/projects/h11/badge/?version=latest\n :target: http://h11.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\nThis is a little HTTP/1.1 library written from scratch in Python,\nheavily inspired by `hyper-h2 `_.\n\nIt's a \"bring-your-own-I/O\" library; h11 contains no IO code\nwhatsoever. This means you can hook h11 up to your favorite network\nAPI, and that could be anything you want: synchronous, threaded,\nasynchronous, or your own implementation of `RFC 6214\n`_ -- h11 won't judge you.\n(Compare this to the current state of the art, where every time a `new\nnetwork API `_ comes along then someone\ngets to start over reimplementing the entire HTTP protocol from\nscratch.) Cory Benfield made an `excellent blog post describing the\nbenefits of this approach\n`_, or if you like video\nthen here's his `PyCon 2016 talk on the same theme\n`_.\n\nThis also means that h11 is not immediately useful out of the box:\nit's a toolkit for building programs that speak HTTP, not something\nthat could directly replace ``requests`` or ``twisted.web`` or\nwhatever. But h11 makes it much easier to implement something like\n``requests`` or ``twisted.web``.\n\nAt a high level, working with h11 goes like this:\n\n1) First, create an ``h11.Connection`` object to track the state of a\n single HTTP/1.1 connection.\n\n2) When you read data off the network, pass it to\n ``conn.receive_data(...)``; you'll get back a list of objects\n representing high-level HTTP \"events\".\n\n3) When you want to send a high-level HTTP event, create the\n corresponding \"event\" object and pass it to ``conn.send(...)``;\n this will give you back some bytes that you can then push out\n through the network.\n\nFor example, a client might instantiate and then send a\n``h11.Request`` object, then zero or more ``h11.Data`` objects for the\nrequest body (e.g., if this is a POST), and then a\n``h11.EndOfMessage`` to indicate the end of the message. Then the\nserver would then send back a ``h11.Response``, some ``h11.Data``, and\nits own ``h11.EndOfMessage``. If either side violates the protocol,\nyou'll get a ``h11.ProtocolError`` exception.\n\nh11 is suitable for implementing both servers and clients, and has a\npleasantly symmetric API: the events you send as a client are exactly\nthe ones that you receive as a server and vice-versa.\n\n`Here's an example of a tiny HTTP client\n`_\n\nIt also has `a fine manual `_.\n\nFAQ\n---\n\n*Whyyyyy?*\n\nI wanted to play with HTTP in `Curio\n`__ and `Trio\n`__, which at the time didn't have any\nHTTP libraries. So I thought, no big deal, Python has, like, a dozen\ndifferent implementations of HTTP, surely I can find one that's\nreusable. I didn't find one, but I did find Cory's call-to-arms\nblog-post. So I figured, well, fine, if I have to implement HTTP from\nscratch, at least I can make sure no-one *else* has to ever again.\n\n*Should I use it?*\n\nMaybe. You should be aware that it's a very young project. But, it's\nfeature complete and has an exhaustive test-suite and complete docs,\nso the next step is for people to try using it and see how it goes\n:-). If you do then please let us know -- if nothing else we'll want\nto talk to you before making any incompatible changes!\n\n*What are the features/limitations?*\n\nRoughly speaking, it's trying to be a robust, complete, and non-hacky\nimplementation of the first \"chapter\" of the HTTP/1.1 spec: `RFC 7230:\nHTTP/1.1 Message Syntax and Routing\n`_. That is, it mostly focuses on\nimplementing HTTP at the level of taking bytes on and off the wire,\nand the headers related to that, and tries to be anal about spec\nconformance. It doesn't know about higher-level concerns like URL\nrouting, conditional GETs, cross-origin cookie policies, or content\nnegotiation. But it does know how to take care of framing,\ncross-version differences in keep-alive handling, and the \"obsolete\nline folding\" rule, so you can focus your energies on the hard /\ninteresting parts for your application, and it tries to support the\nfull specification in the sense that any useful HTTP/1.1 conformant\napplication should be able to use h11.\n\nIt's pure Python, and has no dependencies outside of the standard\nlibrary.\n\nIt has a test suite with 100.0% coverage for both statements and\nbranches.\n\nCurrently it supports Python 3 (testing on 3.7-3.10) and PyPy 3.\nThe last Python 2-compatible version was h11 0.11.x.\n(Originally it had a Cython wrapper for `http-parser\n`_ and a beautiful nested state\nmachine implemented with ``yield from`` to postprocess the output. But\nI had to take these out -- the new *parser* needs fewer lines-of-code\nthan the old *parser wrapper*, is written in pure Python, uses no\nexotic language syntax, and has more features. It's sad, really; that\nold state machine was really slick. I just need a few sentences here\nto mourn that.)\n\nI don't know how fast it is. I haven't benchmarked or profiled it yet,\nso it's probably got a few pointless hot spots, and I've been trying\nto err on the side of simplicity and robustness instead of\nmicro-optimization. But at the architectural level I tried hard to\navoid fundamentally bad decisions, e.g., I believe that all the\nparsing algorithms remain linear-time even in the face of pathological\ninput like slowloris, and there are no byte-by-byte loops. (I also\nbelieve that it maintains bounded memory usage in the face of\narbitrary/pathological input.)\n\nThe whole library is ~800 lines-of-code. You can read and understand\nthe whole thing in less than an hour. Most of the energy invested in\nthis so far has been spent on trying to keep things simple by\nminimizing special-cases and ad hoc state manipulation; even though it\nis now quite small and simple, I'm still annoyed that I haven't\nfigured out how to make it even smaller and simpler. (Unfortunately,\nHTTP does not lend itself to simplicity.)\n\nThe API is ~feature complete and I don't expect the general outlines\nto change much, but you can't judge an API's ergonomics until you\nactually document and use it, so I'd expect some changes in the\ndetails.\n\n*How do I try it?*\n\n.. code-block:: sh\n\n $ pip install h11\n $ git clone git@github.com:python-hyper/h11\n $ cd h11/examples\n $ python basic-client.py\n\nand go from there.\n\n*License?*\n\nMIT\n\n*Code of conduct?*\n\nContributors are requested to follow our `code of conduct\n`_ in\nall project spaces.\n", + "home_page": "https://github.com/python-hyper/h11", + "author": "Nathaniel J. Smith", + "author_email": "njs@pobox.com", + "license": "MIT", + "classifier": [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Topic :: Internet :: WWW/HTTP", + "Topic :: System :: Networking" + ], + "requires_dist": [ + "typing-extensions ; python_version < \"3.8\"" + ], + "requires_python": ">=3.7" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0", + "hashes": { + "sha256": "e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "jedi", + "version": "0.19.1", + "platform": [ + "any" + ], + "summary": "An autocompletion tool for Python that can be used for text editors.", + "description": "####################################################################################\nJedi - an awesome autocompletion, static analysis and refactoring library for Python\n####################################################################################\n\n.. image:: http://isitmaintained.com/badge/open/davidhalter/jedi.svg\n :target: https://github.com/davidhalter/jedi/issues\n :alt: The percentage of open issues and pull requests\n\n.. image:: http://isitmaintained.com/badge/resolution/davidhalter/jedi.svg\n :target: https://github.com/davidhalter/jedi/issues\n :alt: The resolution time is the median time an issue or pull request stays open.\n\n.. image:: https://github.com/davidhalter/jedi/workflows/ci/badge.svg?branch=master\n :target: https://github.com/davidhalter/jedi/actions\n :alt: Tests\n\n.. image:: https://pepy.tech/badge/jedi\n :target: https://pepy.tech/project/jedi\n :alt: PyPI Downloads\n\n\nJedi is a static analysis tool for Python that is typically used in\nIDEs/editors plugins. Jedi has a focus on autocompletion and goto\nfunctionality. Other features include refactoring, code search and finding\nreferences.\n\nJedi has a simple API to work with. There is a reference implementation as a\n`VIM-Plugin `_. Autocompletion in your\nREPL is also possible, IPython uses it natively and for the CPython REPL you\ncan install it. Jedi is well tested and bugs should be rare.\n\nJedi can currently be used with the following editors/projects:\n\n- Vim (jedi-vim_, YouCompleteMe_, deoplete-jedi_, completor.vim_)\n- `Visual Studio Code`_ (via `Python Extension `_)\n- Emacs (Jedi.el_, company-mode_, elpy_, anaconda-mode_, ycmd_)\n- Sublime Text (SublimeJEDI_ [ST2 + ST3], anaconda_ [only ST3])\n- TextMate_ (Not sure if it's actually working)\n- Kate_ version 4.13+ supports it natively, you have to enable it, though. [`see\n `_]\n- Atom_ (autocomplete-python-jedi_)\n- `GNOME Builder`_ (with support for GObject Introspection)\n- Gedit (gedi_)\n- wdb_ - Web Debugger\n- `Eric IDE`_\n- `IPython 6.0.0+ `_\n- `xonsh shell `_ has `jedi extension `_\n\nand many more!\n\nThere are a few language servers that use Jedi:\n\n- `jedi-language-server `_\n- `python-language-server `_ (currently unmaintained)\n- `python-lsp-server `_ (fork from python-language-server)\n- `anakin-language-server `_\n\nHere are some pictures taken from jedi-vim_:\n\n.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_complete.png\n\nCompletion for almost anything:\n\n.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_function.png\n\nDocumentation:\n\n.. image:: https://github.com/davidhalter/jedi/raw/master/docs/_screenshots/screenshot_pydoc.png\n\n\nGet the latest version from `github `_\n(master branch should always be kind of stable/working).\n\nDocs are available at `https://jedi.readthedocs.org/en/latest/\n`_. Pull requests with enhancements\nand/or fixes are awesome and most welcome. Jedi uses `semantic versioning\n`_.\n\nIf you want to stay **up-to-date** with releases, please **subscribe** to this\nmailing list: https://groups.google.com/g/jedi-announce. To subscribe you can\nsimply send an empty email to ``jedi-announce+subscribe@googlegroups.com``.\n\nIssues & Questions\n==================\n\nYou can file issues and questions in the `issue tracker\n`. Alternatively you can also ask on\n`Stack Overflow `_ with\nthe label ``python-jedi``.\n\nInstallation\n============\n\n`Check out the docs `_.\n\nFeatures and Limitations\n========================\n\nJedi's features are listed here:\n`Features `_.\n\nYou can run Jedi on Python 3.6+ but it should also\nunderstand code that is older than those versions. Additionally you should be\nable to use `Virtualenvs `_\nvery well.\n\nTips on how to use Jedi efficiently can be found `here\n`_.\n\nAPI\n---\n\nYou can find a comprehensive documentation for the\n`API here `_.\n\nAutocompletion / Goto / Documentation\n-------------------------------------\n\nThere are the following commands:\n\n- ``jedi.Script.goto``\n- ``jedi.Script.infer``\n- ``jedi.Script.help``\n- ``jedi.Script.complete``\n- ``jedi.Script.get_references``\n- ``jedi.Script.get_signatures``\n- ``jedi.Script.get_context``\n\nThe returned objects are very powerful and are really all you might need.\n\nAutocompletion in your REPL (IPython, etc.)\n-------------------------------------------\n\nJedi is a dependency of IPython. Autocompletion in IPython with Jedi is\ntherefore possible without additional configuration.\n\nHere is an `example video `_ how REPL completion\ncan look like.\nFor the ``python`` shell you can enable tab completion in a `REPL\n`_.\n\nStatic Analysis\n---------------\n\nFor a lot of forms of static analysis, you can try to use\n``jedi.Script(...).get_names``. It will return a list of names that you can\nthen filter and work with. There is also a way to list the syntax errors in a\nfile: ``jedi.Script.get_syntax_errors``.\n\n\nRefactoring\n-----------\n\nJedi supports the following refactorings:\n\n- ``jedi.Script.inline``\n- ``jedi.Script.rename``\n- ``jedi.Script.extract_function``\n- ``jedi.Script.extract_variable``\n\nCode Search\n-----------\n\nThere is support for module search with ``jedi.Script.search``, and project\nsearch for ``jedi.Project.search``. The way to search is either by providing a\nname like ``foo`` or by using dotted syntax like ``foo.bar``. Additionally you\ncan provide the API type like ``class foo.bar.Bar``. There are also the\nfunctions ``jedi.Script.complete_search`` and ``jedi.Project.complete_search``.\n\nDevelopment\n===========\n\nThere's a pretty good and extensive `development documentation\n`_.\n\nTesting\n=======\n\nThe test suite uses ``pytest``::\n\n pip install pytest\n\nIf you want to test only a specific Python version (e.g. Python 3.8), it is as\neasy as::\n\n python3.8 -m pytest\n\nFor more detailed information visit the `testing documentation\n`_.\n\nAcknowledgements\n================\n\nThanks a lot to all the\n`contributors `_!\n\n\n.. _jedi-vim: https://github.com/davidhalter/jedi-vim\n.. _youcompleteme: https://github.com/ycm-core/YouCompleteMe\n.. _deoplete-jedi: https://github.com/zchee/deoplete-jedi\n.. _completor.vim: https://github.com/maralla/completor.vim\n.. _Jedi.el: https://github.com/tkf/emacs-jedi\n.. _company-mode: https://github.com/syohex/emacs-company-jedi\n.. _elpy: https://github.com/jorgenschaefer/elpy\n.. _anaconda-mode: https://github.com/proofit404/anaconda-mode\n.. _ycmd: https://github.com/abingham/emacs-ycmd\n.. _sublimejedi: https://github.com/srusskih/SublimeJEDI\n.. _anaconda: https://github.com/DamnWidget/anaconda\n.. _wdb: https://github.com/Kozea/wdb\n.. _TextMate: https://github.com/lawrenceakka/python-jedi.tmbundle\n.. _Kate: https://kate-editor.org\n.. _Atom: https://atom.io/\n.. _autocomplete-python-jedi: https://atom.io/packages/autocomplete-python-jedi\n.. _GNOME Builder: https://wiki.gnome.org/Apps/Builder\n.. _Visual Studio Code: https://code.visualstudio.com/\n.. _gedi: https://github.com/isamert/gedi\n.. _Eric IDE: https://eric-ide.python-projects.org\n\n\n.. :changelog:\n\nChangelog\n---------\n\nUnreleased\n++++++++++\n\n0.19.1 (2023-10-02)\n+++++++++++++++++++\n\n- Python 3.12 support (Thanks Peter!)\n\n0.19.0 (2023-07-29)\n+++++++++++++++++++\n\n- Python 3.11 support\n- Massive improvements in performance for ``Interpreter`` (e.g. IPython) users.\n This especially affects ``pandas`` users with large datasets.\n- Add ``jedi.settings.allow_unsafe_interpreter_executions`` to make it easier\n for IPython users to avoid unsafe executions.\n\n0.18.2 (2022-11-21)\n+++++++++++++++++++\n\n- Added dataclass-equivalent for attrs.define\n- Find fixtures from Pytest entrypoints; Examples of pytest plugins installed\n like this are pytest-django, pytest-sugar and Faker.\n- Fixed Project.search, when a venv was involved, which is why for example\n `:Pyimport django.db` did not work in some cases in jedi-vim.\n- And many smaller bugfixes\n\n0.18.1 (2021-11-17)\n+++++++++++++++++++\n\n- Implict namespaces are now a separate types in ``Name().type``\n- Python 3.10 support\n- Mostly bugfixes\n\n0.18.0 (2020-12-25)\n+++++++++++++++++++\n\n- Dropped Python 2 and Python 3.5\n- Using ``pathlib.Path()`` as an output instead of ``str`` in most places:\n - ``Project.path``\n - ``Script.path``\n - ``Definition.module_path``\n - ``Refactoring.get_renames``\n - ``Refactoring.get_changed_files``\n- Functions with ``@property`` now return ``property`` instead of ``function``\n in ``Name().type``\n- Started using annotations\n- Better support for the walrus operator\n- Project attributes are now read accessible\n- Removed all deprecations\n\nThis is likely going to be the last minor release before 1.0.\n\n0.17.2 (2020-07-17)\n+++++++++++++++++++\n\n- Added an option to pass environment variables to ``Environment``\n- ``Project(...).path`` exists now\n- Support for Python 3.9\n- A few bugfixes\n\nThis will be the last release that supports Python 2 and Python 3.5.\n``0.18.0`` will be Python 3.6+.\n\n0.17.1 (2020-06-20)\n+++++++++++++++++++\n\n- Django ``Model`` meta class support\n- Django Manager support (completion on Managers/QuerySets)\n- Added Django Stubs to Jedi, thanks to all contributors of the\n `Django Stubs `_ project\n- Added ``SyntaxError.get_message``\n- Python 3.9 support\n- Bugfixes (mostly towards Generics)\n\n0.17.0 (2020-04-14)\n+++++++++++++++++++\n\n- Added ``Project`` support. This allows a user to specify which folders Jedi\n should work with.\n- Added support for Refactoring. The following refactorings have been\n implemented: ``Script.rename``, ``Script.inline``,\n ``Script.extract_variable`` and ``Script.extract_function``.\n- Added ``Script.get_syntax_errors`` to display syntax errors in the current\n script.\n- Added code search capabilities both for individual files and projects. The\n new functions are ``Project.search``, ``Project.complete_search``,\n ``Script.search`` and ``Script.complete_search``.\n- Added ``Script.help`` to make it easier to display a help window to people.\n Now returns pydoc information as well for Python keywords/operators. This\n means that on the class keyword it will now return the docstring of Python's\n builtin function ``help('class')``.\n- The API documentation is now way more readable and complete. Check it out\n under https://jedi.readthedocs.io. A lot of it has been rewritten.\n- Removed Python 3.4 support\n- Many bugfixes\n\nThis is likely going to be the last minor version that supports Python 2 and\nPython3.5. Bugfixes will be provided in 0.17.1+. The next minor/major version\nwill probably be Jedi 1.0.0.\n\n0.16.0 (2020-01-26)\n+++++++++++++++++++\n\n- **Added** ``Script.get_context`` to get information where you currently are.\n- Completions/type inference of **Pytest fixtures**.\n- Tensorflow, Numpy and Pandas completions should now be about **4-10x faster**\n after the first time they are used.\n- Dict key completions are working now. e.g. ``d = {1000: 3}; d[10`` will\n expand to ``1000``.\n- Completion for \"proxies\" works now. These are classes that have a\n ``__getattr__(self, name)`` method that does a ``return getattr(x, name)``.\n after loading them initially.\n- Goto on a function/attribute in a class now goes to the definition in its\n super class.\n- Big **Script API Changes**:\n - The line and column parameters of ``jedi.Script`` are now deprecated\n - ``completions`` deprecated, use ``complete`` instead\n - ``goto_assignments`` deprecated, use ``goto`` instead\n - ``goto_definitions`` deprecated, use ``infer`` instead\n - ``call_signatures`` deprecated, use ``get_signatures`` instead\n - ``usages`` deprecated, use ``get_references`` instead\n - ``jedi.names`` deprecated, use ``jedi.Script(...).get_names()``\n- ``BaseName.goto_assignments`` renamed to ``BaseName.goto``\n- Add follow_imports to ``Name.goto``. Now its signature matches\n ``Script.goto``.\n- **Python 2 support deprecated**. For this release it is best effort. Python 2\n has reached the end of its life and now it's just about a smooth transition.\n Bugs for Python 2 will not be fixed anymore and a third of the tests are\n already skipped.\n- Removed ``settings.no_completion_duplicates``. It wasn't tested and nobody\n was probably using it anyway.\n- Removed ``settings.use_filesystem_cache`` and\n ``settings.additional_dynamic_modules``, they have no usage anymore. Pretty\n much nobody was probably using them.\n\n0.15.2 (2019-12-20)\n+++++++++++++++++++\n\n- Signatures are now detected a lot better\n- Add fuzzy completions with ``Script(...).completions(fuzzy=True)``\n- Files bigger than one MB (about 20kLOC) get cropped to avoid getting\n stuck completely.\n- Many small Bugfixes\n- A big refactoring around contexts/values\n\n0.15.1 (2019-08-13)\n+++++++++++++++++++\n\n- Small bugfix and removal of a print statement\n\n0.15.0 (2019-08-11)\n+++++++++++++++++++\n\n- Added file path completions, there's a **new** ``Completion.type`` now:\n ``path``. Example: ``'/ho`` -> ``'/home/``\n- ``*args``/``**kwargs`` resolving. If possible Jedi replaces the parameters\n with the actual alternatives.\n- Better support for enums/dataclasses\n- When using Interpreter, properties are now executed, since a lot of people\n have complained about this. Discussion in #1299, #1347.\n\nNew APIs:\n\n- ``Name.get_signatures() -> List[Signature]``. Signatures are similar to\n ``CallSignature``. ``Name.params`` is therefore deprecated.\n- ``Signature.to_string()`` to format signatures.\n- ``Signature.params -> List[ParamName]``, ParamName has the\n following additional attributes ``infer_default()``, ``infer_annotation()``,\n ``to_string()``, and ``kind``.\n- ``Name.execute() -> List[Name]``, makes it possible to infer\n return values of functions.\n\n\n0.14.1 (2019-07-13)\n+++++++++++++++++++\n\n- CallSignature.index should now be working a lot better\n- A couple of smaller bugfixes\n\n0.14.0 (2019-06-20)\n+++++++++++++++++++\n\n- Added ``goto_*(prefer_stubs=True)`` as well as ``goto_*(prefer_stubs=True)``\n- Stubs are used now for type inference\n- Typeshed is used for better type inference\n- Reworked Name.full_name, should have more correct return values\n\n0.13.3 (2019-02-24)\n+++++++++++++++++++\n\n- Fixed an issue with embedded Python, see https://github.com/davidhalter/jedi-vim/issues/870\n\n0.13.2 (2018-12-15)\n+++++++++++++++++++\n\n- Fixed a bug that led to Jedi spawning a lot of subprocesses.\n\n0.13.1 (2018-10-02)\n+++++++++++++++++++\n\n- Bugfixes, because tensorflow completions were still slow.\n\n0.13.0 (2018-10-02)\n+++++++++++++++++++\n\n- A small release. Some bug fixes.\n- Remove Python 3.3 support. Python 3.3 support has been dropped by the Python\n foundation.\n- Default environments are now using the same Python version as the Python\n process. In 0.12.x, we used to load the latest Python version on the system.\n- Added ``include_builtins`` as a parameter to usages.\n- ``goto_assignments`` has a new ``follow_builtin_imports`` parameter that\n changes the previous behavior slightly.\n\n0.12.1 (2018-06-30)\n+++++++++++++++++++\n\n- This release forces you to upgrade parso. If you don't, nothing will work\n anymore. Otherwise changes should be limited to bug fixes. Unfortunately Jedi\n still uses a few internals of parso that make it hard to keep compatibility\n over multiple releases. Parso >=0.3.0 is going to be needed.\n\n0.12.0 (2018-04-15)\n+++++++++++++++++++\n\n- Virtualenv/Environment support\n- F-String Completion/Goto Support\n- Cannot crash with segfaults anymore\n- Cleaned up import logic\n- Understand async/await and autocomplete it (including async generators)\n- Better namespace completions\n- Passing tests for Windows (including CI for Windows)\n- Remove Python 2.6 support\n\n0.11.1 (2017-12-14)\n+++++++++++++++++++\n\n- Parso update - the caching layer was broken\n- Better usages - a lot of internal code was ripped out and improved.\n\n0.11.0 (2017-09-20)\n+++++++++++++++++++\n\n- Split Jedi's parser into a separate project called ``parso``.\n- Avoiding side effects in REPL completion.\n- Numpy docstring support should be much better.\n- Moved the `settings.*recursion*` away, they are no longer usable.\n\n0.10.2 (2017-04-05)\n+++++++++++++++++++\n\n- Python Packaging sucks. Some files were not included in 0.10.1.\n\n0.10.1 (2017-04-05)\n+++++++++++++++++++\n\n- Fixed a few very annoying bugs.\n- Prepared the parser to be factored out of Jedi.\n\n0.10.0 (2017-02-03)\n+++++++++++++++++++\n\n- Actual semantic completions for the complete Python syntax.\n- Basic type inference for ``yield from`` PEP 380.\n- PEP 484 support (most of the important features of it). Thanks Claude! (@reinhrst)\n- Added ``get_line_code`` to ``Name`` and ``Completion`` objects.\n- Completely rewritten the type inference engine.\n- A new and better parser for (fast) parsing diffs of Python code.\n\n0.9.0 (2015-04-10)\n++++++++++++++++++\n\n- The import logic has been rewritten to look more like Python's. There is now\n an ``InferState.modules`` import cache, which resembles ``sys.modules``.\n- Integrated the parser of 2to3. This will make refactoring possible. It will\n also be possible to check for error messages (like compiling an AST would give)\n in the future.\n- With the new parser, the type inference also completely changed. It's now\n simpler and more readable.\n- Completely rewritten REPL completion.\n- Added ``jedi.names``, a command to do static analysis. Thanks to that\n sourcegraph guys for sponsoring this!\n- Alpha version of the linter.\n\n\n0.8.1 (2014-07-23)\n+++++++++++++++++++\n\n- Bugfix release, the last release forgot to include files that improve\n autocompletion for builtin libraries. Fixed.\n\n0.8.0 (2014-05-05)\n+++++++++++++++++++\n\n- Memory Consumption for compiled modules (e.g. builtins, sys) has been reduced\n drastically. Loading times are down as well (it takes basically as long as an\n import).\n- REPL completion is starting to become usable.\n- Various small API changes. Generally this release focuses on stability and\n refactoring of internal APIs.\n- Introducing operator precedence, which makes calculating correct Array\n indices and ``__getattr__`` strings possible.\n\n0.7.0 (2013-08-09)\n++++++++++++++++++\n\n- Switched from LGPL to MIT license.\n- Added an Interpreter class to the API to make autocompletion in REPL\n possible.\n- Added autocompletion support for namespace packages.\n- Add sith.py, a new random testing method.\n\n0.6.0 (2013-05-14)\n++++++++++++++++++\n\n- Much faster parser with builtin part caching.\n- A test suite, thanks @tkf.\n\n0.5 versions (2012)\n+++++++++++++++++++\n\n- Initial development.\n\n\n", + "keywords": [ + "python", + "completion", + "refactoring", + "vim" + ], + "home_page": "https://github.com/davidhalter/jedi", + "author": "David Halter", + "author_email": "davidhalter88@gmail.com", + "maintainer": "David Halter", + "maintainer_email": "davidhalter88@gmail.com", + "license": "MIT", + "classifier": [ + "Development Status :: 4 - Beta", + "Environment :: Plugins", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Text Editors :: Integrated Development Environments (IDE)", + "Topic :: Utilities" + ], + "requires_dist": [ + "parso (<0.9.0,>=0.8.3)", + "Jinja2 (==2.11.3) ; extra == 'docs'", + "MarkupSafe (==1.1.1) ; extra == 'docs'", + "Pygments (==2.8.1) ; extra == 'docs'", + "alabaster (==0.7.12) ; extra == 'docs'", + "babel (==2.9.1) ; extra == 'docs'", + "chardet (==4.0.0) ; extra == 'docs'", + "commonmark (==0.8.1) ; extra == 'docs'", + "docutils (==0.17.1) ; extra == 'docs'", + "future (==0.18.2) ; extra == 'docs'", + "idna (==2.10) ; extra == 'docs'", + "imagesize (==1.2.0) ; extra == 'docs'", + "mock (==1.0.1) ; extra == 'docs'", + "packaging (==20.9) ; extra == 'docs'", + "pyparsing (==2.4.7) ; extra == 'docs'", + "pytz (==2021.1) ; extra == 'docs'", + "readthedocs-sphinx-ext (==2.1.4) ; extra == 'docs'", + "recommonmark (==0.5.0) ; extra == 'docs'", + "requests (==2.25.1) ; extra == 'docs'", + "six (==1.15.0) ; extra == 'docs'", + "snowballstemmer (==2.1.0) ; extra == 'docs'", + "sphinx-rtd-theme (==0.4.3) ; extra == 'docs'", + "sphinx (==1.8.5) ; extra == 'docs'", + "sphinxcontrib-serializinghtml (==1.1.4) ; extra == 'docs'", + "sphinxcontrib-websupport (==1.2.4) ; extra == 'docs'", + "urllib3 (==1.26.4) ; extra == 'docs'", + "flake8 (==5.0.4) ; extra == 'qa'", + "mypy (==0.971) ; extra == 'qa'", + "types-setuptools (==67.2.0.1) ; extra == 'qa'", + "Django ; extra == 'testing'", + "attrs ; extra == 'testing'", + "colorama ; extra == 'testing'", + "docopt ; extra == 'testing'", + "pytest (<7.0.0) ; extra == 'testing'" + ], + "requires_python": ">=3.6", + "project_url": [ + "Documentation, https://jedi.readthedocs.io/en/latest/" + ], + "provides_extra": [ + "docs", + "qa", + "testing" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/ee/07/44bd408781594c4d0a027666ef27fab1e441b109dc3b76b4f836f8fd04fe/jsonschema_specifications-2023.12.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c", + "hashes": { + "sha256": "87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "jsonschema-specifications", + "version": "2023.12.1", + "summary": "The JSON Schema meta-schemas and vocabularies, exposed as a Registry", + "description": "=============================\n``jsonschema-specifications``\n=============================\n\n|PyPI| |Pythons| |CI| |ReadTheDocs|\n\nJSON support files from the `JSON Schema Specifications `_ (metaschemas, vocabularies, etc.), packaged for runtime access from Python as a `referencing-based Schema Registry `_.\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/jsonschema-specifications.svg\n :alt: PyPI version\n :target: https://pypi.org/project/jsonschema-specifications/\n\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/jsonschema-specifications.svg\n :alt: Supported Python versions\n :target: https://pypi.org/project/jsonschema-specifications/\n\n.. |CI| image:: https://github.com/python-jsonschema/jsonschema-specifications/workflows/CI/badge.svg\n :alt: Build status\n :target: https://github.com/python-jsonschema/jsonschema-specifications/actions?query=workflow%3ACI\n\n.. |ReadTheDocs| image:: https://readthedocs.org/projects/jsonschema-specifications/badge/?version=stable&style=flat\n :alt: ReadTheDocs status\n :target: https://jsonschema-specifications.readthedocs.io/en/stable/\n", + "description_content_type": "text/x-rst", + "keywords": [ + "data validation", + "json", + "json schema", + "jsonschema", + "validation" + ], + "author": "Julian Berman", + "author_email": "Julian+jsonschema-specifications@GrayVines.com", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: File Formats :: JSON :: JSON Schema" + ], + "requires_dist": [ + "importlib-resources>=1.4.0; python_version < '3.9'", + "referencing>=0.31.0" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://jsonschema-specifications.readthedocs.io/", + "Homepage, https://github.com/python-jsonschema/jsonschema-specifications", + "Issues, https://github.com/python-jsonschema/jsonschema-specifications/issues/", + "Funding, https://github.com/sponsors/Julian", + "Tidelift, https://tidelift.com/subscription/pkg/pypi-jsonschema-specifications?utm_source=pypi-jsonschema-specifications&utm_medium=referral&utm_campaign=pypi-link", + "Source, https://github.com/python-jsonschema/jsonschema-specifications" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/f0/74/c95adcdf032956d9ef6c89a9b8a5152bf73915f8c633f3e3d88d06bd699c/mistune-3.0.2-py3-none-any.whl", + "archive_info": { + "hash": "sha256=71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205", + "hashes": { + "sha256": "71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "mistune", + "version": "3.0.2", + "summary": "A sane and fast Markdown parser with useful plugins and renderers", + "description": "Mistune v3\n==========\n\nA fast yet powerful Python Markdown parser with renderers and plugins.\n\nOverview\n--------\n\nConvert Markdown to HTML with ease:\n\n.. code-block:: python\n\n import mistune\n mistune.html(your_markdown_text)\n\nUseful Links\n------------\n\n1. GitHub: https://github.com/lepture/mistune\n2. Docs: https://mistune.lepture.com/\n\nLicense\n-------\n\nMistune is licensed under BSD. Please see LICENSE for licensing details.\n", + "description_content_type": "text/x-rst", + "author_email": "Hsiaoming Yang ", + "license": "BSD-3-Clause", + "classifier": [ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Text Processing :: Markup" + ], + "requires_python": ">=3.7", + "project_url": [ + "Documentation, https://mistune.lepture.com/", + "Source, https://github.com/lepture/mistune", + "Donate, https://github.com/sponsors/lepture" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/66/e8/00517a23d3eeaed0513e718fbc94aab26eaa1758f5690fc8578839791c79/nbclient-0.10.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f", + "hashes": { + "sha256": "f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "nbclient", + "version": "0.10.0", + "summary": "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor.", + "description": "[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyter/nbclient/main?filepath=binder%2Frun_nbclient.ipynb)\n[![Build Status](https://github.com/jupyter/nbclient/workflows/CI/badge.svg)](https://github.com/jupyter/nbclient/actions)\n[![Documentation Status](https://readthedocs.org/projects/nbclient/badge/?version=latest)](https://nbclient.readthedocs.io/en/latest/?badge=latest)\n[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/)\n[![Python 3.8](https://img.shields.io/badge/python-3.8-blue.svg)](https://www.python.org/downloads/release/python-380/)\n[![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/)\n[![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/)\n[![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n\n# nbclient\n\n**NBClient** lets you **execute** notebooks.\n\nA client library for programmatic notebook execution, **NBClient** is a tool for running Jupyter Notebooks in\ndifferent execution contexts, including the command line.\n\n## Interactive Demo\n\nTo demo **NBClient** interactively, click this Binder badge to start the demo:\n\n[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyter/nbclient/main?filepath=binder%2Frun_nbclient.ipynb)\n\n## Installation\n\nIn a terminal, run:\n\n```\npython3 -m pip install nbclient\n```\n\n## Documentation\n\nSee [ReadTheDocs](https://nbclient.readthedocs.io/en/latest/) for more in-depth details about the project and the\n[API Reference](https://nbclient.readthedocs.io/en/latest/reference/index.html).\n\n## Python Version Support\n\nThis library currently supports Python 3.6+ versions. As minor Python\nversions are officially sunset by the Python org, nbclient will similarly\ndrop support in the future.\n\n## Origins\n\nThis library used to be part of the [nbconvert](https://nbconvert.readthedocs.io/en/latest/) project. NBClient extracted nbconvert's `ExecutePreprocessor`into its own library for easier updating and importing by downstream libraries and applications.\n\n## Relationship to JupyterClient\n\nNBClient and JupyterClient are distinct projects.\n\n`jupyter_client` is a client library for the jupyter protocol. Specifically, `jupyter_client` provides the Python API\nfor starting, managing and communicating with Jupyter kernels.\n\nWhile, nbclient allows notebooks to be run in different execution contexts.\n\n## About the Jupyter Development Team\n\nThe Jupyter Development Team is the set of all contributors to the Jupyter project.\nThis includes all of the Jupyter subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttps://github.com/jupyter/.\n\n## Our Copyright Policy\n\nJupyter uses a shared copyright model. Each contributor maintains copyright\nover their contributions to Jupyter. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the Jupyter\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire Jupyter\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the Jupyter repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n```\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n```\n", + "description_content_type": "text/markdown", + "keywords": [ + "executor", + "jupyter", + "notebook", + "pipeline" + ], + "author_email": "Jupyter Development Team ", + "license": "BSD 3-Clause License\n\nCopyright (c) 2020-, Jupyter Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11" + ], + "requires_dist": [ + "jupyter-client>=6.1.12", + "jupyter-core!=5.0.*,>=4.12", + "nbformat>=5.1", + "traitlets>=5.4", + "pre-commit; extra == 'dev'", + "autodoc-traits; extra == 'docs'", + "mock; extra == 'docs'", + "moto; extra == 'docs'", + "myst-parser; extra == 'docs'", + "nbclient[test]; extra == 'docs'", + "sphinx-book-theme; extra == 'docs'", + "sphinx>=1.7; extra == 'docs'", + "sphinxcontrib-spelling; extra == 'docs'", + "flaky; extra == 'test'", + "ipykernel>=6.19.3; extra == 'test'", + "ipython; extra == 'test'", + "ipywidgets; extra == 'test'", + "nbconvert>=7.0.0; extra == 'test'", + "pytest-asyncio; extra == 'test'", + "pytest-cov>=4.0; extra == 'test'", + "pytest<8,>=7.0; extra == 'test'", + "testpath; extra == 'test'", + "xmltodict; extra == 'test'" + ], + "requires_python": ">=3.8.0", + "project_url": [ + "Documentation, https://nbclient.readthedocs.io", + "Funding, https://numfocus.org/", + "Homepage, https://jupyter.org", + "Source, https://github.com/jupyter/nbclient", + "Tracker, https://github.com/jupyter/nbclient/issues" + ], + "provides_extra": [ + "dev", + "docs", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", + "hashes": { + "sha256": "93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "pandocfilters", + "version": "1.5.1", + "summary": "Utilities for writing pandoc filters in python", + "description": "pandocfilters\n=============\n\nA python module for writing `pandoc `_ filters\n\nWhat are pandoc filters?\n--------------------------\nPandoc filters\nare pipes that read a JSON serialization of the Pandoc AST\nfrom stdin, transform it in some way, and write it to stdout.\nThey can be used with pandoc (>= 1.12) either using pipes ::\n\n pandoc -t json -s | ./caps.py | pandoc -f json\n\nor using the ``--filter`` (or ``-F``) command-line option. ::\n\n pandoc --filter ./caps.py -s\n\nFor more on pandoc filters, see the pandoc documentation under ``--filter``\nand `the tutorial on writing filters`__.\n\n__ http://johnmacfarlane.net/pandoc/scripting.html\n\nFor an alternative library for writing pandoc filters, with\na more \"Pythonic\" design, see `panflute`__.\n\n__ https://github.com/sergiocorreia/panflute\n\nCompatibility\n----------------\nPandoc 1.16 introduced link and image `attributes` to the existing\n`caption` and `target` arguments, requiring a change in pandocfilters\nthat breaks backwards compatibility. Consequently, you should use:\n\n- pandocfilters version <= 1.2.4 for pandoc versions 1.12--1.15, and\n- pandocfilters version >= 1.3.0 for pandoc versions >= 1.16.\n\nPandoc 1.17.3 (pandoc-types 1.17.*) introduced a new JSON format.\npandocfilters 1.4.0 should work with both the old and the new\nformat.\n\nInstalling\n--------------\nRun this inside the present directory::\n\n python setup.py install\n\nOr install from PyPI::\n\n pip install pandocfilters\n\nAvailable functions\n----------------------\nThe main functions ``pandocfilters`` exports are\n\n- ``walk(x, action, format, meta)``\n\n Walk a tree, applying an action to every object. Returns a modified\n tree. An action is a function of the form\n ``action(key, value, format, meta)``, where:\n\n - ``key`` is the type of the pandoc object (e.g. 'Str', 'Para')\n - ``value`` is the contents of the object (e.g. a string for 'Str', a list of\n inline elements for 'Para')\n - ``format`` is the target output format (as supplied by the\n ``format`` argument of ``walk``)\n - ``meta`` is the document's metadata\n\n The return of an action is either:\n\n - ``None``: this means that the object should remain unchanged\n - a pandoc object: this will replace the original object\n - a list of pandoc objects: these will replace the original object;\n the list is merged with the neighbors of the original objects\n (spliced into the list the original object belongs to); returning\n an empty list deletes the object\n\n- ``toJSONFilter(action)``\n\n Like ``toJSONFilters``, but takes a single action as argument.\n\n- ``toJSONFilters(actions)``\n\n Generate a JSON-to-JSON filter from stdin to stdout\n\n The filter:\n\n - reads a JSON-formatted pandoc document from stdin\n - transforms it by walking the tree and performing the actions\n - returns a new JSON-formatted pandoc document to stdout\n\n The argument ``actions`` is a list of functions of the form\n ``action(key, value, format, meta)``, as described in more detail\n under ``walk``.\n\n This function calls ``applyJSONFilters``, with the ``format``\n argument provided by the first command-line argument, if present.\n (Pandoc sets this by default when calling filters.)\n\n- ``applyJSONFilters(actions, source, format=\"\")``\n\n Walk through JSON structure and apply filters\n\n This:\n\n - reads a JSON-formatted pandoc document from a source string\n - transforms it by walking the tree and performing the actions\n - returns a new JSON-formatted pandoc document as a string\n\n The ``actions`` argument is a list of functions (see ``walk`` for a\n full description).\n\n The argument ``source`` is a string encoded JSON object.\n\n The argument ``format`` is a string describing the output format.\n\n Returns a new JSON-formatted pandoc document.\n\n- ``stringify(x)``\n\n Walks the tree x and returns concatenated string content, leaving out\n all formatting.\n\n- ``attributes(attrs)``\n\n Returns an attribute list, constructed from the dictionary attrs.\n\nHow to use\n----------\nMost users will only need ``toJSONFilter``. Here is a simple example\nof its use::\n\n #!/usr/bin/env python\n\n \"\"\"\n Pandoc filter to convert all regular text to uppercase.\n Code, link URLs, etc. are not affected.\n \"\"\"\n\n from pandocfilters import toJSONFilter, Str\n\n def caps(key, value, format, meta):\n if key == 'Str':\n return Str(value.upper())\n\n if __name__ == \"__main__\":\n toJSONFilter(caps)\n\nExamples\n--------\n\nThe examples subdirectory in the source repository contains the\nfollowing filters. These filters should provide a useful starting point\nfor developing your own pandocfilters.\n\n``abc.py``\n Pandoc filter to process code blocks with class ``abc`` containing ABC\n notation into images. Assumes that abcm2ps and ImageMagick's convert\n are in the path. Images are put in the abc-images directory.\n\n``caps.py``\n Pandoc filter to convert all regular text to uppercase. Code, link\n URLs, etc. are not affected.\n\n``blockdiag.py``\n Pandoc filter to process code blocks with class \"blockdiag\" into\n generated images. Needs utils from http://blockdiag.com.\n\n``comments.py``\n Pandoc filter that causes everything between\n ```` and ```` to be ignored.\n The comment lines must appear on lines by themselves, with blank\n lines surrounding\n\n``deemph.py``\n Pandoc filter that causes emphasized text to be displayed in ALL\n CAPS.\n\n``deflists.py``\n Pandoc filter to convert definition lists to bullet lists with the\n defined terms in strong emphasis (for compatibility with standard\n markdown).\n\n``gabc.py``\n Pandoc filter to convert code blocks with class \"gabc\" to LaTeX\n \\\\gabcsnippet commands in LaTeX output, and to images in HTML output.\n\n``graphviz.py``\n Pandoc filter to process code blocks with class ``graphviz`` into\n graphviz-generated images.\n\n``lilypond.py``\n Pandoc filter to process code blocks with class \"ly\" containing\n Lilypond notation.\n\n``metavars.py``\n Pandoc filter to allow interpolation of metadata fields into a\n document. ``%{fields}`` will be replaced by the field's value, assuming\n it is of the type ``MetaInlines`` or ``MetaString``.\n\n``myemph.py``\n Pandoc filter that causes emphasis to be rendered using the custom\n macro ``\\myemph{...}`` rather than ``\\emph{...}`` in latex. Other output\n formats are unaffected.\n\n``plantuml.py``\n Pandoc filter to process code blocks with class ``plantuml`` to images.\n Needs `plantuml.jar` from http://plantuml.com/.\n\n``ditaa.py``\n Pandoc filter to process code blocks with class ``ditaa`` to images.\n Needs `ditaa.jar` from http://ditaa.sourceforge.net/.\n\n``theorem.py``\n Pandoc filter to convert divs with ``class=\"theorem\"`` to LaTeX theorem\n environments in LaTeX output, and to numbered theorems in HTML\n output.\n\n``tikz.py``\n Pandoc filter to process raw latex tikz environments into images.\n Assumes that pdflatex is in the path, and that the standalone\n package is available. Also assumes that ImageMagick's convert is in\n the path. Images are put in the ``tikz-images`` directory.\n\nAPI documentation\n-----------------\n\nBy default most filters use ``get_filename4code`` to\ncreate a directory ``...-images`` to save temporary\nfiles. This directory doesn't get removed as it can be used as a cache so that\nlater pandoc runs don't have to recreate files if they already exist. The\ndirectory is generated in the current directory.\n\nIf you prefer to have a clean directory after running pandoc filters, you\ncan set an environment variable ``PANDOCFILTER_CLEANUP`` to any non-empty value such as `1`\nwhich forces the code to create a temporary directory that will be removed\nby the end of execution.\n", + "keywords": [ + "pandoc" + ], + "home_page": "http://github.com/jgm/pandocfilters", + "author": "John MacFarlane", + "author_email": "fiddlosopher@gmail.com", + "license": "BSD-3-Clause", + "classifier": [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: End Users/Desktop", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Topic :: Text Processing :: Filters", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/ee/fd/ca7bf3869e7caa7a037e23078539467b433a4e01eebd93f77180ab927766/prompt_toolkit-3.0.43-py3-none-any.whl", + "archive_info": { + "hash": "sha256=a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6", + "hashes": { + "sha256": "a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "prompt-toolkit", + "version": "3.0.43", + "summary": "Library for building powerful interactive command lines in Python", + "description": "Python Prompt Toolkit\n=====================\n\n|AppVeyor| |PyPI| |RTD| |License| |Codecov|\n\n.. image :: https://github.com/prompt-toolkit/python-prompt-toolkit/raw/master/docs/images/logo_400px.png\n\n``prompt_toolkit`` *is a library for building powerful interactive command line applications in Python.*\n\nRead the `documentation on readthedocs\n`_.\n\n\nGallery\n*******\n\n`ptpython `_ is an interactive\nPython Shell, build on top of ``prompt_toolkit``.\n\n.. image :: https://github.com/prompt-toolkit/python-prompt-toolkit/raw/master/docs/images/ptpython.png\n\n`More examples `_\n\n\nprompt_toolkit features\n***********************\n\n``prompt_toolkit`` could be a replacement for `GNU readline\n`_, but it can be much\nmore than that.\n\nSome features:\n\n- **Pure Python**.\n- Syntax highlighting of the input while typing. (For instance, with a Pygments lexer.)\n- Multi-line input editing.\n- Advanced code completion.\n- Both Emacs and Vi key bindings. (Similar to readline.)\n- Even some advanced Vi functionality, like named registers and digraphs.\n- Reverse and forward incremental search.\n- Works well with Unicode double width characters. (Chinese input.)\n- Selecting text for copy/paste. (Both Emacs and Vi style.)\n- Support for `bracketed paste `_.\n- Mouse support for cursor positioning and scrolling.\n- Auto suggestions. (Like `fish shell `_.)\n- Multiple input buffers.\n- No global state.\n- Lightweight, the only dependencies are Pygments and wcwidth.\n- Runs on Linux, OS X, FreeBSD, OpenBSD and Windows systems.\n- And much more...\n\nFeel free to create tickets for bugs and feature requests, and create pull\nrequests if you have nice patches that you would like to share with others.\n\n\nInstallation\n************\n\n::\n\n pip install prompt_toolkit\n\nFor Conda, do:\n\n::\n\n conda install -c https://conda.anaconda.org/conda-forge prompt_toolkit\n\n\nAbout Windows support\n*********************\n\n``prompt_toolkit`` is cross platform, and everything that you build on top\nshould run fine on both Unix and Windows systems. Windows support is best on\nrecent Windows 10 builds, for which the command line window supports vt100\nescape sequences. (If not supported, we fall back to using Win32 APIs for color\nand cursor movements).\n\nIt's worth noting that the implementation is a \"best effort of what is\npossible\". Both Unix and Windows terminals have their limitations. But in\ngeneral, the Unix experience will still be a little better.\n\nFor Windows, it's recommended to use either `cmder\n`_ or `conemu `_.\n\nGetting started\n***************\n\nThe most simple example of the library would look like this:\n\n.. code:: python\n\n from prompt_toolkit import prompt\n\n if __name__ == '__main__':\n answer = prompt('Give me some input: ')\n print('You said: %s' % answer)\n\nFor more complex examples, have a look in the ``examples`` directory. All\nexamples are chosen to demonstrate only one thing. Also, don't be afraid to\nlook at the source code. The implementation of the ``prompt`` function could be\na good start.\n\nPhilosophy\n**********\n\nThe source code of ``prompt_toolkit`` should be **readable**, **concise** and\n**efficient**. We prefer short functions focusing each on one task and for which\nthe input and output types are clearly specified. We mostly prefer composition\nover inheritance, because inheritance can result in too much functionality in\nthe same object. We prefer immutable objects where possible (objects don't\nchange after initialization). Reusability is important. We absolutely refrain\nfrom having a changing global state, it should be possible to have multiple\nindependent instances of the same code in the same process. The architecture\nshould be layered: the lower levels operate on primitive operations and data\nstructures giving -- when correctly combined -- all the possible flexibility;\nwhile at the higher level, there should be a simpler API, ready-to-use and\nsufficient for most use cases. Thinking about algorithms and efficiency is\nimportant, but avoid premature optimization.\n\n\n`Projects using prompt_toolkit `_\n***********************************************\n\nSpecial thanks to\n*****************\n\n- `Pygments `_: Syntax highlighter.\n- `wcwidth `_: Determine columns needed for a wide characters.\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/prompt_toolkit.svg\n :target: https://pypi.python.org/pypi/prompt-toolkit/\n :alt: Latest Version\n\n.. |AppVeyor| image:: https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true\n :target: https://ci.appveyor.com/project/prompt-toolkit/python-prompt-toolkit/\n\n.. |RTD| image:: https://readthedocs.org/projects/python-prompt-toolkit/badge/\n :target: https://python-prompt-toolkit.readthedocs.io/en/master/\n\n.. |License| image:: https://img.shields.io/github/license/prompt-toolkit/python-prompt-toolkit.svg\n :target: https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/LICENSE\n\n.. |Codecov| image:: https://codecov.io/gh/prompt-toolkit/python-prompt-toolkit/branch/master/graphs/badge.svg?style=flat\n :target: https://codecov.io/gh/prompt-toolkit/python-prompt-toolkit/\n\n", + "description_content_type": "text/x-rst", + "home_page": "https://github.com/prompt-toolkit/python-prompt-toolkit", + "author": "Jonathan Slenders", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python", + "Topic :: Software Development" + ], + "requires_dist": [ + "wcwidth" + ], + "requires_python": ">=3.7.0" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", + "hashes": { + "sha256": "b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "Pygments", + "version": "2.18.0", + "summary": "Pygments is a syntax highlighting package written in Python.", + "description": "Pygments\n~~~~~~~~\n\nPygments is a syntax highlighting package written in Python.\n\nIt is a generic syntax highlighter suitable for use in code hosting, forums,\nwikis or other applications that need to prettify source code. Highlights\nare:\n\n* a wide range of over 500 languages and other text formats is supported\n* special attention is paid to details, increasing quality by a fair amount\n* support for new languages and formats are added easily\n* a number of output formats, presently HTML, LaTeX, RTF, SVG, all image\n formats that PIL supports and ANSI sequences\n* it is usable as a command-line tool and as a library\n\nCopyright 2006-2024 by the Pygments team, see ``AUTHORS``.\nLicensed under the BSD, see ``LICENSE`` for details.\n", + "description_content_type": "text/x-rst", + "keywords": [ + "syntax", + "highlighting" + ], + "author_email": "Georg Brandl ", + "maintainer": "Matthäus G. Chajdas", + "maintainer_email": "Georg Brandl , Jean Abou Samra ", + "license": "BSD-2-Clause", + "classifier": [ + "Development Status :: 6 - Mature", + "Intended Audience :: Developers", + "Intended Audience :: End Users/Desktop", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Text Processing :: Filters", + "Topic :: Utilities" + ], + "requires_dist": [ + "colorama>=0.4.6; extra == 'windows-terminal'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://pygments.org", + "Documentation, https://pygments.org/docs", + "Source, https://github.com/pygments/pygments", + "Bug Tracker, https://github.com/pygments/pygments/issues", + "Changelog, https://github.com/pygments/pygments/blob/master/CHANGES" + ], + "provides_extra": [ + "plugins", + "windows-terminal" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", + "hashes": { + "sha256": "a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "python-dateutil", + "version": "2.9.0.post0", + "summary": "Extensions to the standard Python datetime module", + "description": "dateutil - powerful extensions to datetime\n==========================================\n\n|pypi| |support| |licence|\n\n|gitter| |readthedocs|\n\n|travis| |appveyor| |pipelines| |coverage|\n\n.. |pypi| image:: https://img.shields.io/pypi/v/python-dateutil.svg?style=flat-square\n :target: https://pypi.org/project/python-dateutil/\n :alt: pypi version\n\n.. |support| image:: https://img.shields.io/pypi/pyversions/python-dateutil.svg?style=flat-square\n :target: https://pypi.org/project/python-dateutil/\n :alt: supported Python version\n\n.. |travis| image:: https://img.shields.io/travis/dateutil/dateutil/master.svg?style=flat-square&label=Travis%20Build\n :target: https://travis-ci.org/dateutil/dateutil\n :alt: travis build status\n\n.. |appveyor| image:: https://img.shields.io/appveyor/ci/dateutil/dateutil/master.svg?style=flat-square&logo=appveyor\n :target: https://ci.appveyor.com/project/dateutil/dateutil\n :alt: appveyor build status\n\n.. |pipelines| image:: https://dev.azure.com/pythondateutilazure/dateutil/_apis/build/status/dateutil.dateutil?branchName=master\n :target: https://dev.azure.com/pythondateutilazure/dateutil/_build/latest?definitionId=1&branchName=master\n :alt: azure pipelines build status\n\n.. |coverage| image:: https://codecov.io/gh/dateutil/dateutil/branch/master/graphs/badge.svg?branch=master\n :target: https://codecov.io/gh/dateutil/dateutil?branch=master\n :alt: Code coverage\n\n.. |gitter| image:: https://badges.gitter.im/dateutil/dateutil.svg\n :alt: Join the chat at https://gitter.im/dateutil/dateutil\n :target: https://gitter.im/dateutil/dateutil\n\n.. |licence| image:: https://img.shields.io/pypi/l/python-dateutil.svg?style=flat-square\n :target: https://pypi.org/project/python-dateutil/\n :alt: licence\n\n.. |readthedocs| image:: https://img.shields.io/readthedocs/dateutil/latest.svg?style=flat-square&label=Read%20the%20Docs\n :alt: Read the documentation at https://dateutil.readthedocs.io/en/latest/\n :target: https://dateutil.readthedocs.io/en/latest/\n\nThe `dateutil` module provides powerful extensions to\nthe standard `datetime` module, available in Python.\n\nInstallation\n============\n`dateutil` can be installed from PyPI using `pip` (note that the package name is\ndifferent from the importable name)::\n\n pip install python-dateutil\n\nDownload\n========\ndateutil is available on PyPI\nhttps://pypi.org/project/python-dateutil/\n\nThe documentation is hosted at:\nhttps://dateutil.readthedocs.io/en/stable/\n\nCode\n====\nThe code and issue tracker are hosted on GitHub:\nhttps://github.com/dateutil/dateutil/\n\nFeatures\n========\n\n* Computing of relative deltas (next month, next year,\n next Monday, last week of month, etc);\n* Computing of relative deltas between two given\n date and/or datetime objects;\n* Computing of dates based on very flexible recurrence rules,\n using a superset of the `iCalendar `_\n specification. Parsing of RFC strings is supported as well.\n* Generic parsing of dates in almost any string format;\n* Timezone (tzinfo) implementations for tzfile(5) format\n files (/etc/localtime, /usr/share/zoneinfo, etc), TZ\n environment string (in all known formats), iCalendar\n format files, given ranges (with help from relative deltas),\n local machine timezone, fixed offset timezone, UTC timezone,\n and Windows registry-based time zones.\n* Internal up-to-date world timezone information based on\n Olson's database.\n* Computing of Easter Sunday dates for any given year,\n using Western, Orthodox or Julian algorithms;\n* A comprehensive test suite.\n\nQuick example\n=============\nHere's a snapshot, just to give an idea about the power of the\npackage. For more examples, look at the documentation.\n\nSuppose you want to know how much time is left, in\nyears/months/days/etc, before the next easter happening on a\nyear with a Friday 13th in August, and you want to get today's\ndate out of the \"date\" unix system command. Here is the code:\n\n.. code-block:: python3\n\n >>> from dateutil.relativedelta import *\n >>> from dateutil.easter import *\n >>> from dateutil.rrule import *\n >>> from dateutil.parser import *\n >>> from datetime import *\n >>> now = parse(\"Sat Oct 11 17:13:46 UTC 2003\")\n >>> today = now.date()\n >>> year = rrule(YEARLY,dtstart=now,bymonth=8,bymonthday=13,byweekday=FR)[0].year\n >>> rdelta = relativedelta(easter(year), today)\n >>> print(\"Today is: %s\" % today)\n Today is: 2003-10-11\n >>> print(\"Year with next Aug 13th on a Friday is: %s\" % year)\n Year with next Aug 13th on a Friday is: 2004\n >>> print(\"How far is the Easter of that year: %s\" % rdelta)\n How far is the Easter of that year: relativedelta(months=+6)\n >>> print(\"And the Easter of that year is: %s\" % (today+rdelta))\n And the Easter of that year is: 2004-04-11\n\nBeing exactly 6 months ahead was **really** a coincidence :)\n\nContributing\n============\n\nWe welcome many types of contributions - bug reports, pull requests (code, infrastructure or documentation fixes). For more information about how to contribute to the project, see the ``CONTRIBUTING.md`` file in the repository.\n\n\nAuthor\n======\nThe dateutil module was written by Gustavo Niemeyer \nin 2003.\n\nIt is maintained by:\n\n* Gustavo Niemeyer 2003-2011\n* Tomi Pieviläinen 2012-2014\n* Yaron de Leeuw 2014-2016\n* Paul Ganssle 2015-\n\nStarting with version 2.4.1 and running until 2.8.2, all source and binary\ndistributions will be signed by a PGP key that has, at the very least, been\nsigned by the key which made the previous release. A table of release signing\nkeys can be found below:\n\n=========== ============================\nReleases Signing key fingerprint\n=========== ============================\n2.4.1-2.8.2 `6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB`_\n=========== ============================\n\nNew releases *may* have signed tags, but binary and source distributions\nuploaded to PyPI will no longer have GPG signatures attached.\n\nContact\n=======\nOur mailing list is available at `dateutil@python.org `_. As it is hosted by the PSF, it is subject to the `PSF code of\nconduct `_.\n\nLicense\n=======\n\nAll contributions after December 1, 2017 released under dual license - either `Apache 2.0 License `_ or the `BSD 3-Clause License `_. Contributions before December 1, 2017 - except those those explicitly relicensed - are released only under the BSD 3-Clause License.\n\n\n.. _6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB:\n https://pgp.mit.edu/pks/lookup?op=vindex&search=0xCD54FCE3D964BEFB\n", + "description_content_type": "text/x-rst", + "home_page": "https://github.com/dateutil/dateutil", + "author": "Gustavo Niemeyer", + "author_email": "gustavo@niemeyer.net", + "maintainer": "Paul Ganssle", + "maintainer_email": "dateutil@python.org", + "license": "Dual License", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Libraries" + ], + "requires_dist": [ + "six >=1.5" + ], + "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7", + "project_url": [ + "Documentation, https://dateutil.readthedocs.io/en/stable/", + "Source, https://github.com/dateutil/dateutil" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl", + "archive_info": { + "hash": "sha256=f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd", + "hashes": { + "sha256": "f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "python-json-logger", + "version": "2.0.7", + "summary": "A python library adding a json log formatter", + "description": "![Build Status](https://github.com/madzak/python-json-logger/actions/workflows/build.yml/badge.svg)\n[![License](https://img.shields.io/pypi/l/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)\n[![Version](https://img.shields.io/pypi/v/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)\n\nOverview\n=======\nThis library is provided to allow standard python logging to output log data as json objects. With JSON we can make our logs more readable by machines and we can stop writing custom parsers for syslog type records.\n\nNews\n=======\nHi, I see this package is quiet alive and I am sorry for ignoring it so long. I will be stepping up my maintenance of this package so please allow me a week to get things back in order (and most likely a new minor version) and I'll post and update here once I am caught up.\n\nInstalling\n==========\nPip:\n\n pip install python-json-logger\n\nPypi:\n\n https://pypi.python.org/pypi/python-json-logger\n\nManual:\n\n python setup.py install\n\nUsage\n=====\n\n## Integrating with Python's logging framework\n\nJson outputs are provided by the JsonFormatter logging formatter. You can add the custom formatter like below:\n\n**Please note: version 0.1.0 has changed the import structure, please update to the following example for proper importing**\n\n```python\n import logging\n from pythonjsonlogger import jsonlogger\n\n logger = logging.getLogger()\n\n logHandler = logging.StreamHandler()\n formatter = jsonlogger.JsonFormatter()\n logHandler.setFormatter(formatter)\n logger.addHandler(logHandler)\n```\n\n## Customizing fields\n\nThe fmt parser can also be overidden if you want to have required fields that differ from the default of just `message`.\n\nThese two invocations are equivalent:\n\n```python\nclass CustomJsonFormatter(jsonlogger.JsonFormatter):\n def parse(self):\n return self._fmt.split(';')\n\nformatter = CustomJsonFormatter('one;two')\n\n# is equivalent to:\n\nformatter = jsonlogger.JsonFormatter('%(one)s %(two)s')\n```\n\nYou can also add extra fields to your json output by specifying a dict in place of message, as well as by specifying an `extra={}` argument.\n\nContents of these dictionaries will be added at the root level of the entry and may override basic fields.\n\nYou can also use the `add_fields` method to add to or generally normalize the set of default set of fields, it is called for every log event. For example, to unify default fields with those provided by [structlog](http://www.structlog.org/) you could do something like this:\n\n```python\nclass CustomJsonFormatter(jsonlogger.JsonFormatter):\n def add_fields(self, log_record, record, message_dict):\n super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)\n if not log_record.get('timestamp'):\n # this doesn't use record.created, so it is slightly off\n now = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ')\n log_record['timestamp'] = now\n if log_record.get('level'):\n log_record['level'] = log_record['level'].upper()\n else:\n log_record['level'] = record.levelname\n\nformatter = CustomJsonFormatter('%(timestamp)s %(level)s %(name)s %(message)s')\n```\n\nItems added to the log record will be included in *every* log message, no matter what the format requires.\n\n## Adding custom object serialization\n\nFor custom handling of object serialization you can specify default json object translator or provide a custom encoder\n\n```python\ndef json_translate(obj):\n if isinstance(obj, MyClass):\n return {\"special\": obj.special}\n\nformatter = jsonlogger.JsonFormatter(json_default=json_translate,\n json_encoder=json.JSONEncoder)\nlogHandler.setFormatter(formatter)\n\nlogger.info({\"special\": \"value\", \"run\": 12})\nlogger.info(\"classic message\", extra={\"special\": \"value\", \"run\": 12})\n```\n\n## Using a Config File\n\nTo use the module with a config file using the [`fileConfig` function](https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig), use the class `pythonjsonlogger.jsonlogger.JsonFormatter`. Here is a sample config file.\n\n```ini\n[loggers]\nkeys = root,custom\n\n[logger_root]\nhandlers =\n\n[logger_custom]\nlevel = INFO\nhandlers = custom\nqualname = custom\n\n[handlers]\nkeys = custom\n\n[handler_custom]\nclass = StreamHandler\nlevel = INFO\nformatter = json\nargs = (sys.stdout,)\n\n[formatters]\nkeys = json\n\n[formatter_json]\nformat = %(message)s\nclass = pythonjsonlogger.jsonlogger.JsonFormatter\n```\n\nExample Output\n==============\n\nSample JSON with a full formatter (basically the log message from the unit test). Every log message will appear on 1 line like a typical logger.\n\n```json\n{\n \"threadName\": \"MainThread\",\n \"name\": \"root\",\n \"thread\": 140735202359648,\n \"created\": 1336281068.506248,\n \"process\": 41937,\n \"processName\": \"MainProcess\",\n \"relativeCreated\": 9.100914001464844,\n \"module\": \"tests\",\n \"funcName\": \"testFormatKeys\",\n \"levelno\": 20,\n \"msecs\": 506.24799728393555,\n \"pathname\": \"tests/tests.py\",\n \"lineno\": 60,\n \"asctime\": [\"12-05-05 22:11:08,506248\"],\n \"message\": \"testing logging format\",\n \"filename\": \"tests.py\",\n \"levelname\": \"INFO\",\n \"special\": \"value\",\n \"run\": 12\n}\n```\n\nExternal Examples\n=================\n\n- [Wesley Tanaka - Structured log files in Python using python-json-logger](http://web.archive.org/web/20201130054012/https://wtanaka.com/node/8201)\n\n- [Archive](https://web.archive.org/web/20201130054012/https://wtanaka.com/node/8201)\n", + "description_content_type": "text/markdown", + "home_page": "http://github.com/madzak/python-json-logger", + "author": "Zakaria Zajac", + "author_email": "zak@madzak.com", + "license": "BSD", + "classifier": [ + "Development Status :: 6 - Mature", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: System :: Logging" + ], + "requires_python": ">=3.6" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/2b/9f/fbade56564ad486809c27b322d0f7e6a89c01f6b4fe208402e90d4443a99/PyYAML-6.0.1-cp312-cp312-win_amd64.whl", + "archive_info": { + "hash": "sha256=0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "hashes": { + "sha256": "0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "PyYAML", + "version": "6.0.1", + "platform": [ + "Any" + ], + "summary": "YAML parser and emitter for Python", + "description": "YAML is a data serialization format designed for human readability\r\nand interaction with scripting languages. PyYAML is a YAML parser\r\nand emitter for Python.\r\n\r\nPyYAML features a complete YAML 1.1 parser, Unicode support, pickle\r\nsupport, capable extension API, and sensible error messages. PyYAML\r\nsupports standard YAML tags and provides Python-specific tags that\r\nallow to represent an arbitrary Python object.\r\n\r\nPyYAML is applicable for a broad range of tasks from complex\r\nconfiguration files to object serialization and persistence.\r\n", + "home_page": "https://pyyaml.org/", + "download_url": "https://pypi.org/project/PyYAML/", + "author": "Kirill Simonov", + "author_email": "xi@resolvent.net", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Cython", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Text Processing :: Markup" + ], + "requires_python": ">=3.6", + "project_url": [ + "Bug Tracker, https://github.com/yaml/pyyaml/issues", + "CI, https://github.com/yaml/pyyaml/actions", + "Documentation, https://pyyaml.org/wiki/PyYAMLDocumentation", + "Mailing lists, http://lists.sourceforge.net/lists/listinfo/yaml-core", + "Source Code, https://github.com/yaml/pyyaml" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/b7/59/2056f61236782a2c86b33906c025d4f4a0b17be0161b63b70fd9e8775d36/referencing-0.35.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de", + "hashes": { + "sha256": "eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "referencing", + "version": "0.35.1", + "summary": "JSON Referencing + Python", + "description": "===============\n``referencing``\n===============\n\n|PyPI| |Pythons| |CI| |ReadTheDocs| |pre-commit|\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/referencing.svg\n :alt: PyPI version\n :target: https://pypi.org/project/referencing/\n\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/referencing.svg\n :alt: Supported Python versions\n :target: https://pypi.org/project/referencing/\n\n.. |CI| image:: https://github.com/python-jsonschema/referencing/workflows/CI/badge.svg\n :alt: Build status\n :target: https://github.com/python-jsonschema/referencing/actions?query=workflow%3ACI\n\n.. |ReadTheDocs| image:: https://readthedocs.org/projects/referencing/badge/?version=stable&style=flat\n :alt: ReadTheDocs status\n :target: https://referencing.readthedocs.io/en/stable/\n\n.. |pre-commit| image:: https://results.pre-commit.ci/badge/github/python-jsonschema/referencing/main.svg\n :alt: pre-commit.ci status\n :target: https://results.pre-commit.ci/latest/github/python-jsonschema/referencing/main\n\n\nAn implementation-agnostic implementation of JSON reference resolution.\n\nSee `the documentation `_ for more details.\n", + "description_content_type": "text/x-rst", + "keywords": [ + "asyncapi", + "json", + "jsonschema", + "openapi", + "referencing" + ], + "author_email": "Julian Berman ", + "classifier": [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: File Formats :: JSON", + "Topic :: File Formats :: JSON :: JSON Schema" + ], + "requires_dist": [ + "attrs>=22.2.0", + "rpds-py>=0.7.0" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://referencing.readthedocs.io/", + "Homepage, https://github.com/python-jsonschema/referencing", + "Issues, https://github.com/python-jsonschema/referencing/issues/", + "Funding, https://github.com/sponsors/Julian", + "Tidelift, https://tidelift.com/subscription/pkg/pypi-referencing?utm_source=pypi-referencing&utm_medium=referral&utm_campaign=pypi-link", + "Changelog, https://referencing.readthedocs.io/en/stable/changes/", + "Source, https://github.com/python-jsonschema/referencing" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", + "hashes": { + "sha256": "2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "rfc3986-validator", + "version": "0.1.1", + "platform": [ + "UNKNOWN" + ], + "summary": "Pure python rfc3986 validator", + "description": "# rfc3986-validator\n\nA pure python RFC3986 validator\n\n\n[![image](https://img.shields.io/pypi/v/rfc3986_validator.svg)](https://pypi.python.org/pypi/rfc3986_validator)\n[![Build Status](https://travis-ci.org/naimetti/rfc3986-validator.svg?branch=master)](https://travis-ci.org/naimetti/rfc3986-validator)\n\n# Install\n\n```shell script\npip install rfc3986-validator\n```\n\n# Usage\n\n```pycon\n>>> from rfc3986_validator import validate_rfc3986\n>>> validate_rfc3986('http://foo.bar?q=Spaces should be encoded')\nFalse\n\n>>> validate_rfc3986('http://foo.com/blah_blah_(wikipedia)')\nTrue\n```\n\nIt also support validate [URI-reference](https://tools.ietf.org/html/rfc3986#page-49) rule \n\n```pycon\n>>> validate_rfc3986('//foo.com/blah_blah', rule='URI_reference')\nTrue\n```\n\n - Free software: MIT license\n\n\n\n", + "description_content_type": "text/markdown", + "keywords": [ + "rfc3986", + "validator" + ], + "home_page": "https://github.com/naimetti/rfc3986-validator", + "author": "Nicolas Aimetti", + "author_email": "naimetti@yahoo.com.ar", + "license": "MIT license", + "classifier": [ + "Development Status :: 2 - Pre-Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/01/7d/8552e329973a198e5e150cc6be068f5cbae797a89e64c02bbd47bd397dee/rpds_py-0.18.1-cp312-none-win_amd64.whl", + "archive_info": { + "hash": "sha256=720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72", + "hashes": { + "sha256": "720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.3", + "name": "rpds-py", + "version": "0.18.1", + "summary": "Python bindings to Rust's persistent data structures (rpds)", + "description": "===========\r\n``rpds.py``\r\n===========\r\n\r\n|PyPI| |Pythons| |CI|\r\n\r\n.. |PyPI| image:: https://img.shields.io/pypi/v/rpds-py.svg\r\n :alt: PyPI version\r\n :target: https://pypi.org/project/rpds-py/\r\n\r\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/rpds-py.svg\r\n :alt: Supported Python versions\r\n :target: https://pypi.org/project/rpds-py/\r\n\r\n.. |CI| image:: https://github.com/crate-py/rpds/workflows/CI/badge.svg\r\n :alt: Build status\r\n :target: https://github.com/crate-py/rpds/actions?query=workflow%3ACI\r\n\r\n.. |ReadTheDocs| image:: https://readthedocs.org/projects/referencing/badge/?version=stable&style=flat\r\n :alt: ReadTheDocs status\r\n :target: https://referencing.readthedocs.io/en/stable/\r\n\r\n\r\nPython bindings to the `Rust rpds crate `_ for persistent data structures.\r\n\r\nWhat's here is quite minimal (in transparency, it was written initially to support replacing ``pyrsistent`` in the `referencing library `_).\r\nIf you see something missing (which is very likely), a PR is definitely welcome to add it.\r\n\r\nInstallation\r\n------------\r\n\r\nThe distribution on PyPI is named ``rpds.py`` (equivalently ``rpds-py``), and thus can be installed via e.g.:\r\n\r\n.. code:: sh\r\n\r\n $ pip install rpds-py\r\n\r\nNote that if you install ``rpds-py`` from source, you will need a Rust toolchain installed, as it is a build-time dependency.\r\nAn example of how to do so in a ``Dockerfile`` can be found `here `_.\r\n\r\nIf you believe you are on a common platform which should have wheels built (i.e. and not need to compile from source), feel free to file an issue or pull request modifying the GitHub action used here to build wheels via ``maturin``.\r\n\r\nUsage\r\n-----\r\n\r\nMethods in general are named similarly to their ``rpds`` counterparts (rather than ``pyrsistent``\\ 's conventions, though probably a full drop-in ``pyrsistent``\\ -compatible wrapper module is a good addition at some point).\r\n\r\n.. code:: python\r\n\r\n >>> from rpds import HashTrieMap, HashTrieSet, List\r\n\r\n >>> m = HashTrieMap({\"foo\": \"bar\", \"baz\": \"quux\"})\r\n >>> m.insert(\"spam\", 37) == HashTrieMap({\"foo\": \"bar\", \"baz\": \"quux\", \"spam\": 37})\r\n True\r\n >>> m.remove(\"foo\") == HashTrieMap({\"baz\": \"quux\"})\r\n True\r\n\r\n >>> s = HashTrieSet({\"foo\", \"bar\", \"baz\", \"quux\"})\r\n >>> s.insert(\"spam\") == HashTrieSet({\"foo\", \"bar\", \"baz\", \"quux\", \"spam\"})\r\n True\r\n >>> s.remove(\"foo\") == HashTrieSet({\"bar\", \"baz\", \"quux\"})\r\n True\r\n\r\n >>> L = List([1, 3, 5])\r\n >>> L.push_front(-1) == List([-1, 1, 3, 5])\r\n True\r\n >>> L.rest == List([3, 5])\r\n True\r\n\n", + "description_content_type": "text/x-rst; charset=UTF-8", + "keywords": [ + "data structures", + "rust", + "persistent" + ], + "author_email": "Julian Berman ", + "license": "MIT", + "classifier": [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Rust", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://rpds.readthedocs.io/", + "Homepage, https://github.com/crate-py/rpds", + "Issues, https://github.com/crate-py/rpds/issues/", + "Funding, https://github.com/sponsors/Julian", + "Tidelift, https://tidelift.com/subscription/pkg/pypi-rpds-py?utm_source=pypi-rpds-py&utm_medium=referral&utm_campaign=pypi-link", + "Source, https://github.com/crate-py/rpds" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "hashes": { + "sha256": "450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "urllib3", + "version": "2.2.1", + "summary": "HTTP library with thread-safe connection pooling, file post, and more.", + "description": "

\n\n![urllib3](https://github.com/urllib3/urllib3/raw/main/docs/_static/banner_github.svg)\n\n

\n\n

\n \"PyPI\n \"Python\n \"Join\n \"Coverage\n \"Build\n \"Documentation
\n \"OpenSSF\n \"SLSA\n \"CII\n

\n\nurllib3 is a powerful, *user-friendly* HTTP client for Python. Much of the\nPython ecosystem already uses urllib3 and you should too.\nurllib3 brings many critical features that are missing from the Python\nstandard libraries:\n\n- Thread safety.\n- Connection pooling.\n- Client-side SSL/TLS verification.\n- File uploads with multipart encoding.\n- Helpers for retrying requests and dealing with HTTP redirects.\n- Support for gzip, deflate, brotli, and zstd encoding.\n- Proxy support for HTTP and SOCKS.\n- 100% test coverage.\n\nurllib3 is powerful and easy to use:\n\n```python3\n>>> import urllib3\n>>> resp = urllib3.request(\"GET\", \"http://httpbin.org/robots.txt\")\n>>> resp.status\n200\n>>> resp.data\nb\"User-agent: *\\nDisallow: /deny\\n\"\n```\n\n## Installing\n\nurllib3 can be installed with [pip](https://pip.pypa.io):\n\n```bash\n$ python -m pip install urllib3\n```\n\nAlternatively, you can grab the latest source code from [GitHub](https://github.com/urllib3/urllib3):\n\n```bash\n$ git clone https://github.com/urllib3/urllib3.git\n$ cd urllib3\n$ pip install .\n```\n\n\n## Documentation\n\nurllib3 has usage and reference documentation at [urllib3.readthedocs.io](https://urllib3.readthedocs.io).\n\n\n## Community\n\nurllib3 has a [community Discord channel](https://discord.gg/urllib3) for asking questions and\ncollaborating with other contributors. Drop by and say hello 👋\n\n\n## Contributing\n\nurllib3 happily accepts contributions. Please see our\n[contributing documentation](https://urllib3.readthedocs.io/en/latest/contributing.html)\nfor some tips on getting started.\n\n\n## Security Disclosures\n\nTo report a security vulnerability, please use the\n[Tidelift security contact](https://tidelift.com/security).\nTidelift will coordinate the fix and disclosure with maintainers.\n\n\n## Maintainers\n\n- [@sethmlarson](https://github.com/sethmlarson) (Seth M. Larson)\n- [@pquentin](https://github.com/pquentin) (Quentin Pradet)\n- [@illia-v](https://github.com/illia-v) (Illia Volochii)\n- [@theacodes](https://github.com/theacodes) (Thea Flowers)\n- [@haikuginger](https://github.com/haikuginger) (Jess Shapiro)\n- [@lukasa](https://github.com/lukasa) (Cory Benfield)\n- [@sigmavirus24](https://github.com/sigmavirus24) (Ian Stapleton Cordasco)\n- [@shazow](https://github.com/shazow) (Andrey Petrov)\n\n👋\n\n\n## Sponsorship\n\nIf your company benefits from this library, please consider [sponsoring its\ndevelopment](https://urllib3.readthedocs.io/en/latest/sponsors.html).\n\n\n## For Enterprise\n\nProfessional support for urllib3 is available as part of the [Tidelift\nSubscription][1]. Tidelift gives software development teams a single source for\npurchasing and maintaining their software, with professional grade assurances\nfrom the experts who know it best, while seamlessly integrating with existing\ntools.\n\n[1]: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme\n", + "description_content_type": "text/markdown", + "keywords": [ + "filepost", + "http", + "httplib", + "https", + "pooling", + "ssl", + "threadsafe", + "urllib" + ], + "author_email": "Andrey Petrov ", + "maintainer_email": "Seth Michael Larson , Quentin Pradet , Illia Volochii ", + "classifier": [ + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Software Development :: Libraries" + ], + "requires_dist": [ + "brotli>=1.0.9; (platform_python_implementation == 'CPython') and extra == 'brotli'", + "brotlicffi>=0.8.0; (platform_python_implementation != 'CPython') and extra == 'brotli'", + "h2<5,>=4; extra == 'h2'", + "pysocks!=1.5.7,<2.0,>=1.5.6; extra == 'socks'", + "zstandard>=0.18.0; extra == 'zstd'" + ], + "requires_python": ">=3.8", + "project_url": [ + "Changelog, https://github.com/urllib3/urllib3/blob/main/CHANGES.rst", + "Documentation, https://urllib3.readthedocs.io", + "Code, https://github.com/urllib3/urllib3", + "Issue tracker, https://github.com/urllib3/urllib3/issues" + ], + "provides_extra": [ + "brotli", + "h2", + "socks", + "zstd" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/37/2c/e34e47c7dee97ba6f01a6203e0383e15b60fb85d78ac9a15cd066f6fe28b/argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", + "archive_info": { + "hash": "sha256=b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", + "hashes": { + "sha256": "b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "argon2-cffi-bindings", + "version": "21.2.0", + "platform": [ + "UNKNOWN" + ], + "summary": "Low-level CFFI bindings for Argon2", + "description": "# Low-level Python CFFI Bindings for Argon2\n\n*argon2-cffi-bindings* provides low-level [*CFFI*](https://cffi.readthedocs.io/) bindings to the [*Argon2*] password hashing algorithm including a vendored version of them.\n\n\nThe currently vendored *Argon2* commit ID is [**`f57e61e`**](https://github.com/P-H-C/phc-winner-argon2/commit/f57e61e19229e23c4445b85494dbf7c07de721cb).\n\n\n> If you want to hash passwords in an application, this package is **not** for you.\n> Have a look at [*argon2-cffi*] with its high-level abstractions!\n\nThese bindings have been extracted from [*argon2-cffi*] and it remains its main consumer.\nHowever, they may be used by other packages that want to use the *Argon2* library without dealing with C-related complexities.\n\n\n## Usage\n\n*argon2-cffi-bindings* is available from [PyPI](https://pypi.org/project/argon2-cffi-bindings/).\nThe provided *CFFI* bindings are compiled in API mode.\n\nBest effort is given to provide binary wheels for as many platforms as possible.\n\n\n### Disabling Vendored Code\n\nA copy of [*Argon2*] is vendored and used by default, but can be disabled if *argon2-cffi-bindings* is installed using:\n\n```console\n$ env ARGON2_CFFI_USE_SYSTEM=1 \\\n python -m pip install --no-binary=argon2-cffi-bindings argon2-cffi-bindings\n```\n\n\n### Overriding Automatic *SSE2* Detection\n\nUsually the build process tries to guess whether or not it should use [*SSE2*](https://en.wikipedia.org/wiki/SSE2)-optimized code (see [`_ffi_build.py`](https://github.com/hynek/argon2-cffi-bindings/blob/main/src/_argon2_cffi_bindings/_ffi_build.py) for details).\nThis can go wrong and is problematic for cross-compiling.\n\nTherefore you can use the `ARGON2_CFFI_USE_SSE2` environment variable to control the process:\n\n- If you set it to ``1``, *argon2-cffi-bindings* will build **with** SSE2 support.\n- If you set it to ``0``, *argon2-cffi-bindings* will build **without** SSE2 support.\n- If you set it to anything else, it will be ignored and *argon2-cffi-bindings* will try to guess.\n\nHowever, if our heuristics fail you, we would welcome a bug report.\n\n\n### Python API\n\nSince this package is intended to be an implementation detail, it uses a private module name to prevent your users from using it by accident.\n\nTherefore you have to import the symbols from `_argon2_cffi_bindings`:\n\n```python\nfrom _argon2_cffi_bindings import ffi, lib\n```\n\nPlease refer to [*cffi* documentation](https://cffi.readthedocs.io/en/latest/using.html) on how to use the `ffi` and `lib` objects.\n\nThe list of symbols that are provided can be found in the [`_ffi_build.py` file](https://github.com/hynek/argon2-cffi-bindings/blob/main/src/_argon2_cffi_bindings/_ffi_build.py).\n\n[*Argon2*]: https://github.com/p-h-c/phc-winner-argon2\n[*argon2-cffi*]: https://argon2-cffi.readthedocs.io/\n\n\n## Project Information\n\n*argon2-cffi-bindings* is available under the MIT license, available from [PyPI](https://pypi.org/project/argon2-cffi-bindings/), the source code and documentation can be found on [GitHub](https://github.com/hynek/argon2-cffi-bindings).\n\n*argon2-cffi-bindings* targets Python 3.6 and later, including PyPy3.\n\n\n### Credits & License\n\n*argon2-cffi-bindings* is written and maintained by [Hynek Schlawack](https://hynek.me/about/).\nIt is released under the [MIT license](https://github.com/hynek/argon2-cffi/blob/main/LICENSE>).\n\nThe development is kindly supported by [Variomedia AG](https://www.variomedia.de/).\n\nThe authors of *Argon2* were very helpful to get the library to compile on ancient versions of Visual Studio for ancient versions of Python.\n\nThe documentation quotes frequently in verbatim from the *Argon2* [paper](https://www.password-hashing.net/argon2-specs.pdf) to avoid mistakes by rephrasing.\n\n\n#### Vendored Code\n\nThe original *Argon2* repo can be found at .\n\nExcept for the components listed below, the *Argon2* code in this repository is copyright (c) 2015 Daniel Dinu, Dmitry Khovratovich (main authors), Jean-Philippe Aumasson and Samuel Neves, and under [CC0] license.\n\nThe string encoding routines in src/encoding.c are copyright (c) 2015 Thomas Pornin, and under [CC0] license.\n\nThe [*BLAKE2*](https://www.blake2.net) code in ``src/blake2/`` is copyright (c) Samuel Neves, 2013-2015, and under [CC0] license.\n\n[CC0]: https://creativecommons.org/publicdomain/zero/1.0/\n\n\n", + "description_content_type": "text/markdown", + "keywords": [ + "password", + "hash", + "hashing", + "security", + "bindings", + "cffi" + ], + "home_page": "https://github.com/hynek/argon2-cffi-bindings", + "author": "Hynek Schlawack", + "author_email": "hs@ox.cx", + "maintainer": "Hynek Schlawack", + "maintainer_email": "hs@ox.cx", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Programming Language :: Python", + "Topic :: Security :: Cryptography", + "Topic :: Security", + "Topic :: Software Development :: Libraries :: Python Modules" + ], + "requires_dist": [ + "cffi (>=1.0.1)", + "pytest ; extra == 'dev'", + "cogapp ; extra == 'dev'", + "pre-commit ; extra == 'dev'", + "wheel ; extra == 'dev'", + "pytest ; extra == 'tests'" + ], + "requires_python": ">=3.6", + "project_url": [ + "Source Code, https://github.com/hynek/argon2-cffi-bindings", + "Funding, https://github.com/sponsors/hynek", + "Tidelift, https://tidelift.com/subscription/pkg/pypi-argon2-cffi?utm_source=pypi-argon2-cffi&utm_medium=pypi", + "Ko-fi, https://ko-fi.com/the_hynek" + ], + "provides_extra": [ + "dev", + "tests" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", + "archive_info": { + "hash": "sha256=b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", + "hashes": { + "sha256": "b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "beautifulsoup4", + "version": "4.12.3", + "summary": "Screen-scraping library", + "description": "Beautiful Soup is a library that makes it easy to scrape information\nfrom web pages. It sits atop an HTML or XML parser, providing Pythonic\nidioms for iterating, searching, and modifying the parse tree.\n\n# Quick start\n\n```\n>>> from bs4 import BeautifulSoup\n>>> soup = BeautifulSoup(\"

SomebadHTML\")\n>>> print(soup.prettify())\n\n \n

\n Some\n \n bad\n \n HTML\n \n \n

\n \n\n>>> soup.find(text=\"bad\")\n'bad'\n>>> soup.i\nHTML\n#\n>>> soup = BeautifulSoup(\"SomebadXML\", \"xml\")\n#\n>>> print(soup.prettify())\n\n\n Some\n \n bad\n \n XML\n \n\n```\n\nTo go beyond the basics, [comprehensive documentation is available](https://www.crummy.com/software/BeautifulSoup/bs4/doc/).\n\n# Links\n\n* [Homepage](https://www.crummy.com/software/BeautifulSoup/bs4/)\n* [Documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)\n* [Discussion group](https://groups.google.com/group/beautifulsoup/)\n* [Development](https://code.launchpad.net/beautifulsoup/)\n* [Bug tracker](https://bugs.launchpad.net/beautifulsoup/)\n* [Complete changelog](https://bazaar.launchpad.net/~leonardr/beautifulsoup/bs4/view/head:/CHANGELOG)\n\n# Note on Python 2 sunsetting\n\nBeautiful Soup's support for Python 2 was discontinued on December 31,\n2020: one year after the sunset date for Python 2 itself. From this\npoint onward, new Beautiful Soup development will exclusively target\nPython 3. The final release of Beautiful Soup 4 to support Python 2\nwas 4.9.3.\n\n# Supporting the project\n\nIf you use Beautiful Soup as part of your professional work, please consider a\n[Tidelift subscription](https://tidelift.com/subscription/pkg/pypi-beautifulsoup4?utm_source=pypi-beautifulsoup4&utm_medium=referral&utm_campaign=readme).\nThis will support many of the free software projects your organization\ndepends on, not just Beautiful Soup.\n\nIf you use Beautiful Soup for personal projects, the best way to say\nthank you is to read\n[Tool Safety](https://www.crummy.com/software/BeautifulSoup/zine/), a zine I\nwrote about what Beautiful Soup has taught me about software\ndevelopment.\n\n# Building the documentation\n\nThe bs4/doc/ directory contains full documentation in Sphinx\nformat. Run `make html` in that directory to create HTML\ndocumentation.\n\n# Running the unit tests\n\nBeautiful Soup supports unit test discovery using Pytest:\n\n```\n$ pytest\n```\n\n", + "description_content_type": "text/markdown", + "keywords": [ + "HTML", + "XML", + "parse", + "soup" + ], + "author_email": "Leonard Richardson ", + "license": "MIT License", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Text Processing :: Markup :: HTML", + "Topic :: Text Processing :: Markup :: SGML", + "Topic :: Text Processing :: Markup :: XML" + ], + "requires_dist": [ + "soupsieve>1.2", + "cchardet; extra == 'cchardet'", + "chardet; extra == 'chardet'", + "charset-normalizer; extra == 'charset-normalizer'", + "html5lib; extra == 'html5lib'", + "lxml; extra == 'lxml'" + ], + "requires_python": ">=3.6.0", + "project_url": [ + "Download, https://www.crummy.com/software/BeautifulSoup/bs4/download/", + "Homepage, https://www.crummy.com/software/BeautifulSoup/bs4/" + ], + "provides_extra": [ + "cchardet", + "chardet", + "charset-normalizer", + "html5lib", + "lxml" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", + "hashes": { + "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "colorama", + "version": "0.4.6", + "summary": "Cross-platform colored terminal text.", + "description": ".. image:: https://img.shields.io/pypi/v/colorama.svg\n :target: https://pypi.org/project/colorama/\n :alt: Latest Version\n\n.. image:: https://img.shields.io/pypi/pyversions/colorama.svg\n :target: https://pypi.org/project/colorama/\n :alt: Supported Python versions\n\n.. image:: https://github.com/tartley/colorama/actions/workflows/test.yml/badge.svg\n :target: https://github.com/tartley/colorama/actions/workflows/test.yml\n :alt: Build Status\n\nColorama\n========\n\nMakes ANSI escape character sequences (for producing colored terminal text and\ncursor positioning) work under MS Windows.\n\n.. |donate| image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif\n :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama¤cy_code=USD\n :alt: Donate with Paypal\n\n`PyPI for releases `_ |\n`Github for source `_ |\n`Colorama for enterprise on Tidelift `_\n\nIf you find Colorama useful, please |donate| to the authors. Thank you!\n\nInstallation\n------------\n\nTested on CPython 2.7, 3.7, 3.8, 3.9 and 3.10 and Pypy 2.7 and 3.8.\n\nNo requirements other than the standard library.\n\n.. code-block:: bash\n\n pip install colorama\n # or\n conda install -c anaconda colorama\n\nDescription\n-----------\n\nANSI escape character sequences have long been used to produce colored terminal\ntext and cursor positioning on Unix and Macs. Colorama makes this work on\nWindows, too, by wrapping ``stdout``, stripping ANSI sequences it finds (which\nwould appear as gobbledygook in the output), and converting them into the\nappropriate win32 calls to modify the state of the terminal. On other platforms,\nColorama does nothing.\n\nThis has the upshot of providing a simple cross-platform API for printing\ncolored terminal text from Python, and has the happy side-effect that existing\napplications or libraries which use ANSI sequences to produce colored output on\nLinux or Macs can now also work on Windows, simply by calling\n``colorama.just_fix_windows_console()`` (since v0.4.6) or ``colorama.init()``\n(all versions, but may have other side-effects – see below).\n\nAn alternative approach is to install ``ansi.sys`` on Windows machines, which\nprovides the same behaviour for all applications running in terminals. Colorama\nis intended for situations where that isn't easy (e.g., maybe your app doesn't\nhave an installer.)\n\nDemo scripts in the source code repository print some colored text using\nANSI sequences. Compare their output under Gnome-terminal's built in ANSI\nhandling, versus on Windows Command-Prompt using Colorama:\n\n.. image:: https://github.com/tartley/colorama/raw/master/screenshots/ubuntu-demo.png\n :width: 661\n :height: 357\n :alt: ANSI sequences on Ubuntu under gnome-terminal.\n\n.. image:: https://github.com/tartley/colorama/raw/master/screenshots/windows-demo.png\n :width: 668\n :height: 325\n :alt: Same ANSI sequences on Windows, using Colorama.\n\nThese screenshots show that, on Windows, Colorama does not support ANSI 'dim\ntext'; it looks the same as 'normal text'.\n\nUsage\n-----\n\nInitialisation\n..............\n\nIf the only thing you want from Colorama is to get ANSI escapes to work on\nWindows, then run:\n\n.. code-block:: python\n\n from colorama import just_fix_windows_console\n just_fix_windows_console()\n\nIf you're on a recent version of Windows 10 or better, and your stdout/stderr\nare pointing to a Windows console, then this will flip the magic configuration\nswitch to enable Windows' built-in ANSI support.\n\nIf you're on an older version of Windows, and your stdout/stderr are pointing to\na Windows console, then this will wrap ``sys.stdout`` and/or ``sys.stderr`` in a\nmagic file object that intercepts ANSI escape sequences and issues the\nappropriate Win32 calls to emulate them.\n\nIn all other circumstances, it does nothing whatsoever. Basically the idea is\nthat this makes Windows act like Unix with respect to ANSI escape handling.\n\nIt's safe to call this function multiple times. It's safe to call this function\non non-Windows platforms, but it won't do anything. It's safe to call this\nfunction when one or both of your stdout/stderr are redirected to a file – it\nwon't do anything to those streams.\n\nAlternatively, you can use the older interface with more features (but also more\npotential footguns):\n\n.. code-block:: python\n\n from colorama import init\n init()\n\nThis does the same thing as ``just_fix_windows_console``, except for the\nfollowing differences:\n\n- It's not safe to call ``init`` multiple times; you can end up with multiple\n layers of wrapping and broken ANSI support.\n\n- Colorama will apply a heuristic to guess whether stdout/stderr support ANSI,\n and if it thinks they don't, then it will wrap ``sys.stdout`` and\n ``sys.stderr`` in a magic file object that strips out ANSI escape sequences\n before printing them. This happens on all platforms, and can be convenient if\n you want to write your code to emit ANSI escape sequences unconditionally, and\n let Colorama decide whether they should actually be output. But note that\n Colorama's heuristic is not particularly clever.\n\n- ``init`` also accepts explicit keyword args to enable/disable various\n functionality – see below.\n\nTo stop using Colorama before your program exits, simply call ``deinit()``.\nThis will restore ``stdout`` and ``stderr`` to their original values, so that\nColorama is disabled. To resume using Colorama again, call ``reinit()``; it is\ncheaper than calling ``init()`` again (but does the same thing).\n\nMost users should depend on ``colorama >= 0.4.6``, and use\n``just_fix_windows_console``. The old ``init`` interface will be supported\nindefinitely for backwards compatibility, but we don't plan to fix any issues\nwith it, also for backwards compatibility.\n\nColored Output\n..............\n\nCross-platform printing of colored text can then be done using Colorama's\nconstant shorthand for ANSI escape sequences. These are deliberately\nrudimentary, see below.\n\n.. code-block:: python\n\n from colorama import Fore, Back, Style\n print(Fore.RED + 'some red text')\n print(Back.GREEN + 'and with a green background')\n print(Style.DIM + 'and in dim text')\n print(Style.RESET_ALL)\n print('back to normal now')\n\n...or simply by manually printing ANSI sequences from your own code:\n\n.. code-block:: python\n\n print('\\033[31m' + 'some red text')\n print('\\033[39m') # and reset to default color\n\n...or, Colorama can be used in conjunction with existing ANSI libraries\nsuch as the venerable `Termcolor `_\nthe fabulous `Blessings `_,\nor the incredible `_Rich `_.\n\nIf you wish Colorama's Fore, Back and Style constants were more capable,\nthen consider using one of the above highly capable libraries to generate\ncolors, etc, and use Colorama just for its primary purpose: to convert\nthose ANSI sequences to also work on Windows:\n\nSIMILARLY, do not send PRs adding the generation of new ANSI types to Colorama.\nWe are only interested in converting ANSI codes to win32 API calls, not\nshortcuts like the above to generate ANSI characters.\n\n.. code-block:: python\n\n from colorama import just_fix_windows_console\n from termcolor import colored\n\n # use Colorama to make Termcolor work on Windows too\n just_fix_windows_console()\n\n # then use Termcolor for all colored text output\n print(colored('Hello, World!', 'green', 'on_red'))\n\nAvailable formatting constants are::\n\n Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.\n Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.\n Style: DIM, NORMAL, BRIGHT, RESET_ALL\n\n``Style.RESET_ALL`` resets foreground, background, and brightness. Colorama will\nperform this reset automatically on program exit.\n\nThese are fairly well supported, but not part of the standard::\n\n Fore: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX\n Back: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX\n\nCursor Positioning\n..................\n\nANSI codes to reposition the cursor are supported. See ``demos/demo06.py`` for\nan example of how to generate them.\n\nInit Keyword Args\n.................\n\n``init()`` accepts some ``**kwargs`` to override default behaviour.\n\ninit(autoreset=False):\n If you find yourself repeatedly sending reset sequences to turn off color\n changes at the end of every print, then ``init(autoreset=True)`` will\n automate that:\n\n .. code-block:: python\n\n from colorama import init\n init(autoreset=True)\n print(Fore.RED + 'some red text')\n print('automatically back to default color again')\n\ninit(strip=None):\n Pass ``True`` or ``False`` to override whether ANSI codes should be\n stripped from the output. The default behaviour is to strip if on Windows\n or if output is redirected (not a tty).\n\ninit(convert=None):\n Pass ``True`` or ``False`` to override whether to convert ANSI codes in the\n output into win32 calls. The default behaviour is to convert if on Windows\n and output is to a tty (terminal).\n\ninit(wrap=True):\n On Windows, Colorama works by replacing ``sys.stdout`` and ``sys.stderr``\n with proxy objects, which override the ``.write()`` method to do their work.\n If this wrapping causes you problems, then this can be disabled by passing\n ``init(wrap=False)``. The default behaviour is to wrap if ``autoreset`` or\n ``strip`` or ``convert`` are True.\n\n When wrapping is disabled, colored printing on non-Windows platforms will\n continue to work as normal. To do cross-platform colored output, you can\n use Colorama's ``AnsiToWin32`` proxy directly:\n\n .. code-block:: python\n\n import sys\n from colorama import init, AnsiToWin32\n init(wrap=False)\n stream = AnsiToWin32(sys.stderr).stream\n\n # Python 2\n print >>stream, Fore.BLUE + 'blue text on stderr'\n\n # Python 3\n print(Fore.BLUE + 'blue text on stderr', file=stream)\n\nRecognised ANSI Sequences\n.........................\n\nANSI sequences generally take the form::\n\n ESC [ ; ... \n\nWhere ```` is an integer, and ```` is a single letter. Zero or\nmore params are passed to a ````. If no params are passed, it is\ngenerally synonymous with passing a single zero. No spaces exist in the\nsequence; they have been inserted here simply to read more easily.\n\nThe only ANSI sequences that Colorama converts into win32 calls are::\n\n ESC [ 0 m # reset all (colors and brightness)\n ESC [ 1 m # bright\n ESC [ 2 m # dim (looks same as normal brightness)\n ESC [ 22 m # normal brightness\n\n # FOREGROUND:\n ESC [ 30 m # black\n ESC [ 31 m # red\n ESC [ 32 m # green\n ESC [ 33 m # yellow\n ESC [ 34 m # blue\n ESC [ 35 m # magenta\n ESC [ 36 m # cyan\n ESC [ 37 m # white\n ESC [ 39 m # reset\n\n # BACKGROUND\n ESC [ 40 m # black\n ESC [ 41 m # red\n ESC [ 42 m # green\n ESC [ 43 m # yellow\n ESC [ 44 m # blue\n ESC [ 45 m # magenta\n ESC [ 46 m # cyan\n ESC [ 47 m # white\n ESC [ 49 m # reset\n\n # cursor positioning\n ESC [ y;x H # position cursor at x across, y down\n ESC [ y;x f # position cursor at x across, y down\n ESC [ n A # move cursor n lines up\n ESC [ n B # move cursor n lines down\n ESC [ n C # move cursor n characters forward\n ESC [ n D # move cursor n characters backward\n\n # clear the screen\n ESC [ mode J # clear the screen\n\n # clear the line\n ESC [ mode K # clear the line\n\nMultiple numeric params to the ``'m'`` command can be combined into a single\nsequence::\n\n ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background\n\nAll other ANSI sequences of the form ``ESC [ ; ... ``\nare silently stripped from the output on Windows.\n\nAny other form of ANSI sequence, such as single-character codes or alternative\ninitial characters, are not recognised or stripped. It would be cool to add\nthem though. Let me know if it would be useful for you, via the Issues on\nGitHub.\n\nStatus & Known Problems\n-----------------------\n\nI've personally only tested it on Windows XP (CMD, Console2), Ubuntu\n(gnome-terminal, xterm), and OS X.\n\nSome valid ANSI sequences aren't recognised.\n\nIf you're hacking on the code, see `README-hacking.md`_. ESPECIALLY, see the\nexplanation there of why we do not want PRs that allow Colorama to generate new\ntypes of ANSI codes.\n\nSee outstanding issues and wish-list:\nhttps://github.com/tartley/colorama/issues\n\nIf anything doesn't work for you, or doesn't do what you expected or hoped for,\nI'd love to hear about it on that issues list, would be delighted by patches,\nand would be happy to grant commit access to anyone who submits a working patch\nor two.\n\n.. _README-hacking.md: README-hacking.md\n\nLicense\n-------\n\nCopyright Jonathan Hartley & Arnon Yaari, 2013-2020. BSD 3-Clause license; see\nLICENSE file.\n\nProfessional support\n--------------------\n\n.. |tideliftlogo| image:: https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png\n :alt: Tidelift\n :target: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme\n\n.. list-table::\n :widths: 10 100\n\n * - |tideliftlogo|\n - Professional support for colorama is available as part of the\n `Tidelift Subscription`_.\n Tidelift gives software development teams a single source for purchasing\n and maintaining their software, with professional grade assurances from\n the experts who know it best, while seamlessly integrating with existing\n tools.\n\n.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme\n\nThanks\n------\n\nSee the CHANGELOG for more thanks!\n\n* Marc Schlaich (schlamar) for a ``setup.py`` fix for Python2.5.\n* Marc Abramowitz, reported & fixed a crash on exit with closed ``stdout``,\n providing a solution to issue #7's setuptools/distutils debate,\n and other fixes.\n* User 'eryksun', for guidance on correctly instantiating ``ctypes.windll``.\n* Matthew McCormick for politely pointing out a longstanding crash on non-Win.\n* Ben Hoyt, for a magnificent fix under 64-bit Windows.\n* Jesse at Empty Square for submitting a fix for examples in the README.\n* User 'jamessp', an observant documentation fix for cursor positioning.\n* User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7\n fix.\n* Julien Stuyck, for wisely suggesting Python3 compatible updates to README.\n* Daniel Griffith for multiple fabulous patches.\n* Oscar Lesta for a valuable fix to stop ANSI chars being sent to non-tty\n output.\n* Roger Binns, for many suggestions, valuable feedback, & bug reports.\n* Tim Golden for thought and much appreciated feedback on the initial idea.\n* User 'Zearin' for updates to the README file.\n* John Szakmeister for adding support for light colors\n* Charles Merriam for adding documentation to demos\n* Jurko for a fix on 64-bit Windows CPython2.5 w/o ctypes\n* Florian Bruhin for a fix when stdout or stderr are None\n* Thomas Weininger for fixing ValueError on Windows\n* Remi Rampin for better Github integration and fixes to the README file\n* Simeon Visser for closing a file handle using 'with' and updating classifiers\n to include Python 3.3 and 3.4\n* Andy Neff for fixing RESET of LIGHT_EX colors.\n* Jonathan Hartley for the initial idea and implementation.\n", + "description_content_type": "text/x-rst", + "keywords": [ + "ansi", + "color", + "colour", + "crossplatform", + "terminal", + "text", + "windows", + "xplatform" + ], + "author_email": "Jonathan Hartley ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Terminals" + ], + "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7", + "project_url": [ + "Homepage, https://github.com/tartley/colorama" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", + "hashes": { + "sha256": "b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "decorator", + "version": "5.1.1", + "platform": [ + "All" + ], + "summary": "Decorators for Humans", + "description": "Decorators for Humans\n=====================\n\nThe goal of the decorator module is to make it easy to define\nsignature-preserving function decorators and decorator factories.\nIt also includes an implementation of multiple dispatch and other niceties\n(please check the docs). It is released under a two-clauses\nBSD license, i.e. basically you can do whatever you want with it but I am not\nresponsible.\n\nInstallation\n-------------\n\nIf you are lazy, just perform\n\n ``$ pip install decorator``\n\nwhich will install just the module on your system.\n\nIf you prefer to install the full distribution from source, including\nthe documentation, clone the `GitHub repo`_ or download the tarball_, unpack it and run\n\n ``$ pip install .``\n\nin the main directory, possibly as superuser.\n\n.. _tarball: https://pypi.org/project/decorator/#files\n.. _GitHub repo: https://github.com/micheles/decorator\n\nTesting\n--------\n\nIf you have the source code installation you can run the tests with\n\n `$ python src/tests/test.py -v`\n\nor (if you have setuptools installed)\n\n `$ python setup.py test`\n\nNotice that you may run into trouble if in your system there\nis an older version of the decorator module; in such a case remove the\nold version. It is safe even to copy the module `decorator.py` over\nan existing one, since we kept backward-compatibility for a long time.\n\nRepository\n---------------\n\nThe project is hosted on GitHub. You can look at the source here:\n\n https://github.com/micheles/decorator\n\nDocumentation\n---------------\n\nThe documentation has been moved to https://github.com/micheles/decorator/blob/master/docs/documentation.md\n\nFrom there you can get a PDF version by simply using the print\nfunctionality of your browser.\n\nHere is the documentation for previous versions of the module:\n\nhttps://github.com/micheles/decorator/blob/4.3.2/docs/tests.documentation.rst\nhttps://github.com/micheles/decorator/blob/4.2.1/docs/tests.documentation.rst\nhttps://github.com/micheles/decorator/blob/4.1.2/docs/tests.documentation.rst\nhttps://github.com/micheles/decorator/blob/4.0.0/documentation.rst\nhttps://github.com/micheles/decorator/blob/3.4.2/documentation.rst\n\nFor the impatient\n-----------------\n\nHere is an example of how to define a family of decorators tracing slow\noperations:\n\n.. code-block:: python\n\n from decorator import decorator\n\n @decorator\n def warn_slow(func, timelimit=60, *args, **kw):\n t0 = time.time()\n result = func(*args, **kw)\n dt = time.time() - t0\n if dt > timelimit:\n logging.warn('%s took %d seconds', func.__name__, dt)\n else:\n logging.info('%s took %d seconds', func.__name__, dt)\n return result\n\n @warn_slow # warn if it takes more than 1 minute\n def preprocess_input_files(inputdir, tempdir):\n ...\n\n @warn_slow(timelimit=600) # warn if it takes more than 10 minutes\n def run_calculation(tempdir, outdir):\n ...\n\nEnjoy!\n\n\n", + "keywords": [ + "decorators", + "generic", + "utility" + ], + "home_page": "https://github.com/micheles/decorator", + "author": "Michele Simionato", + "author_email": "michele.simionato@gmail.com", + "license": "new BSD License", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities" + ], + "requires_python": ">=3.5" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", + "hashes": { + "sha256": "a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "defusedxml", + "version": "0.7.1", + "platform": [ + "all" + ], + "summary": "XML bomb protection for Python stdlib modules", + "description": "===================================================\ndefusedxml -- defusing XML bombs and other exploits\n===================================================\n\n.. image:: https://img.shields.io/pypi/v/defusedxml.svg\n :target: https://pypi.org/project/defusedxml/\n :alt: Latest Version\n\n.. image:: https://img.shields.io/pypi/pyversions/defusedxml.svg\n :target: https://pypi.org/project/defusedxml/\n :alt: Supported Python versions\n\n.. image:: https://travis-ci.org/tiran/defusedxml.svg?branch=master\n :target: https://travis-ci.org/tiran/defusedxml\n :alt: Travis CI\n\n.. image:: https://codecov.io/github/tiran/defusedxml/coverage.svg?branch=master\n :target: https://codecov.io/github/tiran/defusedxml?branch=master\n :alt: codecov\n\n.. image:: https://img.shields.io/pypi/dm/defusedxml.svg\n :target: https://pypistats.org/packages/defusedxml\n :alt: PyPI downloads\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :target: https://github.com/psf/black\n :alt: Code style: black\n\n..\n\n \"It's just XML, what could probably go wrong?\"\n\nChristian Heimes \n\nSynopsis\n========\n\nThe results of an attack on a vulnerable XML library can be fairly dramatic.\nWith just a few hundred **Bytes** of XML data an attacker can occupy several\n**Gigabytes** of memory within **seconds**. An attacker can also keep\nCPUs busy for a long time with a small to medium size request. Under some\ncircumstances it is even possible to access local files on your\nserver, to circumvent a firewall, or to abuse services to rebound attacks to\nthird parties.\n\nThe attacks use and abuse less common features of XML and its parsers. The\nmajority of developers are unacquainted with features such as processing\ninstructions and entity expansions that XML inherited from SGML. At best\nthey know about ```` from experience with HTML but they are not\naware that a document type definition (DTD) can generate an HTTP request\nor load a file from the file system.\n\nNone of the issues is new. They have been known for a long time. Billion\nlaughs was first reported in 2003. Nevertheless some XML libraries and\napplications are still vulnerable and even heavy users of XML are\nsurprised by these features. It's hard to say whom to blame for the\nsituation. It's too short sighted to shift all blame on XML parsers and\nXML libraries for using insecure default settings. After all they\nproperly implement XML specifications. Application developers must not rely\nthat a library is always configured for security and potential harmful data\nby default.\n\n\n.. contents:: Table of Contents\n :depth: 2\n\n\nAttack vectors\n==============\n\nbillion laughs / exponential entity expansion\n---------------------------------------------\n\nThe `Billion Laughs`_ attack -- also known as exponential entity expansion --\nuses multiple levels of nested entities. The original example uses 9 levels\nof 10 expansions in each level to expand the string ``lol`` to a string of\n3 * 10 :sup:`9` bytes, hence the name \"billion laughs\". The resulting string\noccupies 3 GB (2.79 GiB) of memory; intermediate strings require additional\nmemory. Because most parsers don't cache the intermediate step for every\nexpansion it is repeated over and over again. It increases the CPU load even\nmore.\n\nAn XML document of just a few hundred bytes can disrupt all services on a\nmachine within seconds.\n\nExample XML::\n\n \n \n \n \n ]>\n &d;\n\n\nquadratic blowup entity expansion\n---------------------------------\n\nA quadratic blowup attack is similar to a `Billion Laughs`_ attack; it abuses\nentity expansion, too. Instead of nested entities it repeats one large entity\nwith a couple of thousand chars over and over again. The attack isn't as\nefficient as the exponential case but it avoids triggering countermeasures of\nparsers against heavily nested entities. Some parsers limit the depth and\nbreadth of a single entity but not the total amount of expanded text\nthroughout an entire XML document.\n\nA medium-sized XML document with a couple of hundred kilobytes can require a\ncouple of hundred MB to several GB of memory. When the attack is combined\nwith some level of nested expansion an attacker is able to achieve a higher\nratio of success.\n\n::\n\n \n ]>\n &a;&a;&a;... repeat\n\n\nexternal entity expansion (remote)\n----------------------------------\n\nEntity declarations can contain more than just text for replacement. They can\nalso point to external resources by public identifiers or system identifiers.\nSystem identifiers are standard URIs. When the URI is a URL (e.g. a\n``http://`` locator) some parsers download the resource from the remote\nlocation and embed them into the XML document verbatim.\n\nSimple example of a parsed external entity::\n\n \n ]>\n \n\nThe case of parsed external entities works only for valid XML content. The\nXML standard also supports unparsed external entities with a\n``NData declaration``.\n\nExternal entity expansion opens the door to plenty of exploits. An attacker\ncan abuse a vulnerable XML library and application to rebound and forward\nnetwork requests with the IP address of the server. It highly depends\non the parser and the application what kind of exploit is possible. For\nexample:\n\n* An attacker can circumvent firewalls and gain access to restricted\n resources as all the requests are made from an internal and trustworthy\n IP address, not from the outside.\n* An attacker can abuse a service to attack, spy on or DoS your servers but\n also third party services. The attack is disguised with the IP address of\n the server and the attacker is able to utilize the high bandwidth of a big\n machine.\n* An attacker can exhaust additional resources on the machine, e.g. with\n requests to a service that doesn't respond or responds with very large\n files.\n* An attacker may gain knowledge, when, how often and from which IP address\n an XML document is accessed.\n* An attacker could send mail from inside your network if the URL handler\n supports ``smtp://`` URIs.\n\n\nexternal entity expansion (local file)\n--------------------------------------\n\nExternal entities with references to local files are a sub-case of external\nentity expansion. It's listed as an extra attack because it deserves extra\nattention. Some XML libraries such as lxml disable network access by default\nbut still allow entity expansion with local file access by default. Local\nfiles are either referenced with a ``file://`` URL or by a file path (either\nrelative or absolute).\n\nAn attacker may be able to access and download all files that can be read by\nthe application process. This may include critical configuration files, too.\n\n::\n\n \n ]>\n \n\n\nDTD retrieval\n-------------\n\nThis case is similar to external entity expansion, too. Some XML libraries\nlike Python's xml.dom.pulldom retrieve document type definitions from remote\nor local locations. Several attack scenarios from the external entity case\napply to this issue as well.\n\n::\n\n \n \n \n \n text\n \n\n\nPython XML Libraries\n====================\n\n.. csv-table:: vulnerabilities and features\n :header: \"kind\", \"sax\", \"etree\", \"minidom\", \"pulldom\", \"xmlrpc\", \"lxml\", \"genshi\"\n :widths: 24, 7, 8, 8, 7, 8, 8, 8\n :stub-columns: 0\n\n \"billion laughs\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"False (1)\", \"False (5)\"\n \"quadratic blowup\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"False (5)\"\n \"external entity expansion (remote)\", \"**True**\", \"False (3)\", \"False (4)\", \"**True**\", \"false\", \"False (1)\", \"False (5)\"\n \"external entity expansion (local file)\", \"**True**\", \"False (3)\", \"False (4)\", \"**True**\", \"false\", \"**True**\", \"False (5)\"\n \"DTD retrieval\", \"**True**\", \"False\", \"False\", \"**True**\", \"false\", \"False (1)\", \"False\"\n \"gzip bomb\", \"False\", \"False\", \"False\", \"False\", \"**True**\", \"**partly** (2)\", \"False\"\n \"xpath support (7)\", \"False\", \"False\", \"False\", \"False\", \"False\", \"**True**\", \"False\"\n \"xsl(t) support (7)\", \"False\", \"False\", \"False\", \"False\", \"False\", \"**True**\", \"False\"\n \"xinclude support (7)\", \"False\", \"**True** (6)\", \"False\", \"False\", \"False\", \"**True** (6)\", \"**True**\"\n \"C library\", \"expat\", \"expat\", \"expat\", \"expat\", \"expat\", \"libxml2\", \"expat\"\n\n1. Lxml is protected against billion laughs attacks and doesn't do network\n lookups by default.\n2. libxml2 and lxml are not directly vulnerable to gzip decompression bombs\n but they don't protect you against them either.\n3. xml.etree doesn't expand entities and raises a ParserError when an entity\n occurs.\n4. minidom doesn't expand entities and simply returns the unexpanded entity\n verbatim.\n5. genshi.input of genshi 0.6 doesn't support entity expansion and raises a\n ParserError when an entity occurs.\n6. Library has (limited) XInclude support but requires an additional step to\n process inclusion.\n7. These are features but they may introduce exploitable holes, see\n `Other things to consider`_\n\n\nSettings in standard library\n----------------------------\n\n\nxml.sax.handler Features\n........................\n\nfeature_external_ges (http://xml.org/sax/features/external-general-entities)\n disables external entity expansion\n\nfeature_external_pes (http://xml.org/sax/features/external-parameter-entities)\n the option is ignored and doesn't modify any functionality\n\nDOM xml.dom.xmlbuilder.Options\n..............................\n\nexternal_parameter_entities\n ignored\n\nexternal_general_entities\n ignored\n\nexternal_dtd_subset\n ignored\n\nentities\n unsure\n\n\ndefusedxml\n==========\n\nThe `defusedxml package`_ (`defusedxml on PyPI`_)\ncontains several Python-only workarounds and fixes\nfor denial of service and other vulnerabilities in Python's XML libraries.\nIn order to benefit from the protection you just have to import and use the\nlisted functions / classes from the right defusedxml module instead of the\noriginal module. Merely `defusedxml.xmlrpc`_ is implemented as monkey patch.\n\nInstead of::\n\n >>> from xml.etree.ElementTree import parse\n >>> et = parse(xmlfile)\n\nalter code to::\n\n >>> from defusedxml.ElementTree import parse\n >>> et = parse(xmlfile)\n\nAdditionally the package has an **untested** function to monkey patch\nall stdlib modules with ``defusedxml.defuse_stdlib()``.\n\nAll functions and parser classes accept three additional keyword arguments.\nThey return either the same objects as the original functions or compatible\nsubclasses.\n\nforbid_dtd (default: False)\n disallow XML with a ```` processing instruction and raise a\n *DTDForbidden* exception when a DTD processing instruction is found.\n\nforbid_entities (default: True)\n disallow XML with ```` declarations inside the DTD and raise an\n *EntitiesForbidden* exception when an entity is declared.\n\nforbid_external (default: True)\n disallow any access to remote or local resources in external entities\n or DTD and raising an *ExternalReferenceForbidden* exception when a DTD\n or entity references an external resource.\n\n\ndefusedxml (package)\n--------------------\n\nDefusedXmlException, DTDForbidden, EntitiesForbidden,\nExternalReferenceForbidden, NotSupportedError\n\ndefuse_stdlib() (*experimental*)\n\n\ndefusedxml.cElementTree\n-----------------------\n\n**NOTE** ``defusedxml.cElementTree`` is deprecated and will be removed in a\nfuture release. Import from ``defusedxml.ElementTree`` instead.\n\nparse(), iterparse(), fromstring(), XMLParser\n\n\ndefusedxml.ElementTree\n-----------------------\n\nparse(), iterparse(), fromstring(), XMLParser\n\n\ndefusedxml.expatreader\n----------------------\n\ncreate_parser(), DefusedExpatParser\n\n\ndefusedxml.sax\n--------------\n\nparse(), parseString(), make_parser()\n\n\ndefusedxml.expatbuilder\n-----------------------\n\nparse(), parseString(), DefusedExpatBuilder, DefusedExpatBuilderNS\n\n\ndefusedxml.minidom\n------------------\n\nparse(), parseString()\n\n\ndefusedxml.pulldom\n------------------\n\nparse(), parseString()\n\n\ndefusedxml.xmlrpc\n-----------------\n\nThe fix is implemented as monkey patch for the stdlib's xmlrpc package (3.x)\nor xmlrpclib module (2.x). The function `monkey_patch()` enables the fixes,\n`unmonkey_patch()` removes the patch and puts the code in its former state.\n\nThe monkey patch protects against XML related attacks as well as\ndecompression bombs and excessively large requests or responses. The default\nsetting is 30 MB for requests, responses and gzip decompression. You can\nmodify the default by changing the module variable `MAX_DATA`. A value of\n`-1` disables the limit.\n\n\ndefusedxml.lxml\n---------------\n\n**DEPRECATED** The module is deprecated and will be removed in a future\nrelease.\n\nThe module acts as an *example* how you could protect code that uses\nlxml.etree. It implements a custom Element class that filters out\nEntity instances, a custom parser factory and a thread local storage for\nparser instances. It also has a check_docinfo() function which inspects\na tree for internal or external DTDs and entity declarations. In order to\ncheck for entities lxml > 3.0 is required.\n\nparse(), fromstring()\nRestrictedElement, GlobalParserTLS, getDefaultParser(), check_docinfo()\n\n\ndefusedexpat\n============\n\nThe `defusedexpat package`_ (`defusedexpat on PyPI`_)\ncomes with binary extensions and a\n`modified expat`_ library instead of the standard `expat parser`_. It's\nbasically a stand-alone version of the patches for Python's standard\nlibrary C extensions.\n\nModifications in expat\n----------------------\n\nnew definitions::\n\n XML_BOMB_PROTECTION\n XML_DEFAULT_MAX_ENTITY_INDIRECTIONS\n XML_DEFAULT_MAX_ENTITY_EXPANSIONS\n XML_DEFAULT_RESET_DTD\n\nnew XML_FeatureEnum members::\n\n XML_FEATURE_MAX_ENTITY_INDIRECTIONS\n XML_FEATURE_MAX_ENTITY_EXPANSIONS\n XML_FEATURE_IGNORE_DTD\n\nnew XML_Error members::\n\n XML_ERROR_ENTITY_INDIRECTIONS\n XML_ERROR_ENTITY_EXPANSION\n\nnew API functions::\n\n int XML_GetFeature(XML_Parser parser,\n enum XML_FeatureEnum feature,\n long *value);\n int XML_SetFeature(XML_Parser parser,\n enum XML_FeatureEnum feature,\n long value);\n int XML_GetFeatureDefault(enum XML_FeatureEnum feature,\n long *value);\n int XML_SetFeatureDefault(enum XML_FeatureEnum feature,\n long value);\n\nXML_FEATURE_MAX_ENTITY_INDIRECTIONS\n Limit the amount of indirections that are allowed to occur during the\n expansion of a nested entity. A counter starts when an entity reference\n is encountered. It resets after the entity is fully expanded. The limit\n protects the parser against exponential entity expansion attacks (aka\n billion laughs attack). When the limit is exceeded the parser stops and\n fails with `XML_ERROR_ENTITY_INDIRECTIONS`.\n A value of 0 disables the protection.\n\n Supported range\n 0 .. UINT_MAX\n Default\n 40\n\nXML_FEATURE_MAX_ENTITY_EXPANSIONS\n Limit the total length of all entity expansions throughout the entire\n document. The lengths of all entities are accumulated in a parser variable.\n The setting protects against quadratic blowup attacks (lots of expansions\n of a large entity declaration). When the sum of all entities exceeds\n the limit, the parser stops and fails with `XML_ERROR_ENTITY_EXPANSION`.\n A value of 0 disables the protection.\n\n Supported range\n 0 .. UINT_MAX\n Default\n 8 MiB\n\nXML_FEATURE_RESET_DTD\n Reset all DTD information after the block has been parsed. When\n the flag is set (default: false) all DTD information after the\n endDoctypeDeclHandler has been called. The flag can be set inside the\n endDoctypeDeclHandler. Without DTD information any entity reference in\n the document body leads to `XML_ERROR_UNDEFINED_ENTITY`.\n\n Supported range\n 0, 1\n Default\n 0\n\n\nHow to avoid XML vulnerabilities\n================================\n\nBest practices\n--------------\n\n* Don't allow DTDs\n* Don't expand entities\n* Don't resolve externals\n* Limit parse depth\n* Limit total input size\n* Limit parse time\n* Favor a SAX or iterparse-like parser for potential large data\n* Validate and properly quote arguments to XSL transformations and\n XPath queries\n* Don't use XPath expression from untrusted sources\n* Don't apply XSL transformations that come untrusted sources\n\n(based on Brad Hill's `Attacking XML Security`_)\n\n\nOther things to consider\n========================\n\nXML, XML parsers and processing libraries have more features and possible\nissue that could lead to DoS vulnerabilities or security exploits in\napplications. I have compiled an incomplete list of theoretical issues that\nneed further research and more attention. The list is deliberately pessimistic\nand a bit paranoid, too. It contains things that might go wrong under daffy\ncircumstances.\n\n\nattribute blowup / hash collision attack\n----------------------------------------\n\nXML parsers may use an algorithm with quadratic runtime O(n :sup:`2`) to\nhandle attributes and namespaces. If it uses hash tables (dictionaries) to\nstore attributes and namespaces the implementation may be vulnerable to\nhash collision attacks, thus reducing the performance to O(n :sup:`2`) again.\nIn either case an attacker is able to forge a denial of service attack with\nan XML document that contains thousands upon thousands of attributes in\na single node.\n\nI haven't researched yet if expat, pyexpat or libxml2 are vulnerable.\n\n\ndecompression bomb\n------------------\n\nThe issue of decompression bombs (aka `ZIP bomb`_) apply to all XML libraries\nthat can parse compressed XML stream like gzipped HTTP streams or LZMA-ed\nfiles. For an attacker it can reduce the amount of transmitted data by three\nmagnitudes or more. Gzip is able to compress 1 GiB zeros to roughly 1 MB,\nlzma is even better::\n\n $ dd if=/dev/zero bs=1M count=1024 | gzip > zeros.gz\n $ dd if=/dev/zero bs=1M count=1024 | lzma -z > zeros.xy\n $ ls -sh zeros.*\n 1020K zeros.gz\n 148K zeros.xy\n\nNone of Python's standard XML libraries decompress streams except for\n``xmlrpclib``. The module is vulnerable \nto decompression bombs.\n\nlxml can load and process compressed data through libxml2 transparently.\nlibxml2 can handle even very large blobs of compressed data efficiently\nwithout using too much memory. But it doesn't protect applications from\ndecompression bombs. A carefully written SAX or iterparse-like approach can\nbe safe.\n\n\nProcessing Instruction\n----------------------\n\n`PI`_'s like::\n\n \n\nmay impose more threats for XML processing. It depends if and how a\nprocessor handles processing instructions. The issue of URL retrieval with\nnetwork or local file access apply to processing instructions, too.\n\n\nOther DTD features\n------------------\n\n`DTD`_ has more features like ````. I haven't researched how\nthese features may be a security threat.\n\n\nXPath\n-----\n\nXPath statements may introduce DoS vulnerabilities. Code should never execute\nqueries from untrusted sources. An attacker may also be able to create an XML\ndocument that makes certain XPath queries costly or resource hungry.\n\n\nXPath injection attacks\n-----------------------\n\nXPath injeciton attacks pretty much work like SQL injection attacks.\nArguments to XPath queries must be quoted and validated properly, especially\nwhen they are taken from the user. The page `Avoid the dangers of XPath injection`_\nlist some ramifications of XPath injections.\n\nPython's standard library doesn't have XPath support. Lxml supports\nparameterized XPath queries which does proper quoting. You just have to use\nits xpath() method correctly::\n\n # DON'T\n >>> tree.xpath(\"/tag[@id='%s']\" % value)\n\n # instead do\n >>> tree.xpath(\"/tag[@id=$tagid]\", tagid=name)\n\n\nXInclude\n--------\n\n`XML Inclusion`_ is another way to load and include external files::\n\n \n \n \n\nThis feature should be disabled when XML files from an untrusted source are\nprocessed. Some Python XML libraries and libxml2 support XInclude but don't\nhave an option to sandbox inclusion and limit it to allowed directories.\n\n\nXMLSchema location\n------------------\n\nA validating XML parser may download schema files from the information in a\n``xsi:schemaLocation`` attribute.\n\n::\n\n \n \n\n\nXSL Transformation\n------------------\n\nYou should keep in mind that XSLT is a Turing complete language. Never\nprocess XSLT code from unknown or untrusted source! XSLT processors may\nallow you to interact with external resources in ways you can't even imagine.\nSome processors even support extensions that allow read/write access to file\nsystem, access to JRE objects or scripting with Jython.\n\nExample from `Attacking XML Security`_ for Xalan-J::\n\n \n \n \n \n \n \n \n \n\n\nRelated CVEs\n============\n\nCVE-2013-1664\n Unrestricted entity expansion induces DoS vulnerabilities in Python XML\n libraries (XML bomb)\n\nCVE-2013-1665\n External entity expansion in Python XML libraries inflicts potential\n security flaws and DoS vulnerabilities\n\n\nOther languages / frameworks\n=============================\n\nSeveral other programming languages and frameworks are vulnerable as well. A\ncouple of them are affected by the fact that libxml2 up to 2.9.0 has no\nprotection against quadratic blowup attacks. Most of them have potential\ndangerous default settings for entity expansion and external entities, too.\n\nPerl\n----\n\nPerl's XML::Simple is vulnerable to quadratic entity expansion and external\nentity expansion (both local and remote).\n\n\nRuby\n----\n\nRuby's REXML document parser is vulnerable to entity expansion attacks\n(both quadratic and exponential) but it doesn't do external entity\nexpansion by default. In order to counteract entity expansion you have to\ndisable the feature::\n\n REXML::Document.entity_expansion_limit = 0\n\nlibxml-ruby and hpricot don't expand entities in their default configuration.\n\n\nPHP\n---\n\nPHP's SimpleXML API is vulnerable to quadratic entity expansion and loads\nentities from local and remote resources. The option ``LIBXML_NONET`` disables\nnetwork access but still allows local file access. ``LIBXML_NOENT`` seems to\nhave no effect on entity expansion in PHP 5.4.6.\n\n\nC# / .NET / Mono\n----------------\n\nInformation in `XML DoS and Defenses (MSDN)`_ suggest that .NET is\nvulnerable with its default settings. The article contains code snippets\nhow to create a secure XML reader::\n\n XmlReaderSettings settings = new XmlReaderSettings();\n settings.ProhibitDtd = false;\n settings.MaxCharactersFromEntities = 1024;\n settings.XmlResolver = null;\n XmlReader reader = XmlReader.Create(stream, settings);\n\n\nJava\n----\n\nUntested. The documentation of Xerces and its `Xerces SecurityMananger`_\nsounds like Xerces is also vulnerable to billion laugh attacks with its\ndefault settings. It also does entity resolving when an\n``org.xml.sax.EntityResolver`` is configured. I'm not yet sure about the\ndefault setting here.\n\nJava specialists suggest to have a custom builder factory::\n\n DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();\n builderFactory.setXIncludeAware(False);\n builderFactory.setExpandEntityReferences(False);\n builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, True);\n # either\n builderFactory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", True);\n # or if you need DTDs\n builderFactory.setFeature(\"http://xml.org/sax/features/external-general-entities\", False);\n builderFactory.setFeature(\"http://xml.org/sax/features/external-parameter-entities\", False);\n builderFactory.setFeature(\"http://apache.org/xml/features/nonvalidating/load-external-dtd\", False);\n builderFactory.setFeature(\"http://apache.org/xml/features/nonvalidating/load-dtd-grammar\", False);\n\n\nTODO\n====\n\n* DOM: Use xml.dom.xmlbuilder options for entity handling\n* SAX: take feature_external_ges and feature_external_pes (?) into account\n* test experimental monkey patching of stdlib modules\n* improve documentation\n\n\nLicense\n=======\n\nCopyright (c) 2013-2017 by Christian Heimes \n\nLicensed to PSF under a Contributor Agreement.\n\nSee https://www.python.org/psf/license for licensing details.\n\n\nAcknowledgements\n================\n\nBrett Cannon (Python Core developer)\n review and code cleanup\n\nAntoine Pitrou (Python Core developer)\n code review\n\nAaron Patterson, Ben Murphy and Michael Koziarski (Ruby community)\n Many thanks to Aaron, Ben and Michael from the Ruby community for their\n report and assistance.\n\nThierry Carrez (OpenStack)\n Many thanks to Thierry for his report to the Python Security Response\n Team on behalf of the OpenStack security team.\n\nCarl Meyer (Django)\n Many thanks to Carl for his report to PSRT on behalf of the Django security\n team.\n\nDaniel Veillard (libxml2)\n Many thanks to Daniel for his insight and assistance with libxml2.\n\nsemantics GmbH (https://www.semantics.de/)\n Many thanks to my employer semantics for letting me work on the issue\n during working hours as part of semantics's open source initiative.\n\n\nReferences\n==========\n\n* `XML DoS and Defenses (MSDN)`_\n* `Billion Laughs`_ on Wikipedia\n* `ZIP bomb`_ on Wikipedia\n* `Configure SAX parsers for secure processing`_\n* `Testing for XML Injection`_\n\n.. _defusedxml package: https://github.com/tiran/defusedxml\n.. _defusedxml on PyPI: https://pypi.python.org/pypi/defusedxml\n.. _defusedexpat package: https://github.com/tiran/defusedexpat\n.. _defusedexpat on PyPI: https://pypi.python.org/pypi/defusedexpat\n.. _modified expat: https://github.com/tiran/expat\n.. _expat parser: http://expat.sourceforge.net/\n.. _Attacking XML Security: https://www.isecpartners.com/media/12976/iSEC-HILL-Attacking-XML-Security-bh07.pdf\n.. _Billion Laughs: https://en.wikipedia.org/wiki/Billion_laughs\n.. _XML DoS and Defenses (MSDN): https://msdn.microsoft.com/en-us/magazine/ee335713.aspx\n.. _ZIP bomb: https://en.wikipedia.org/wiki/Zip_bomb\n.. _DTD: https://en.wikipedia.org/wiki/Document_Type_Definition\n.. _PI: https://en.wikipedia.org/wiki/Processing_Instruction\n.. _Avoid the dangers of XPath injection: http://www.ibm.com/developerworks/xml/library/x-xpathinjection/index.html\n.. _Configure SAX parsers for secure processing: http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html\n.. _Testing for XML Injection: https://www.owasp.org/index.php/Testing_for_XML_Injection_(OWASP-DV-008)\n.. _Xerces SecurityMananger: https://xerces.apache.org/xerces2-j/javadocs/xerces2/org/apache/xerces/util/SecurityManager.html\n.. _XML Inclusion: https://www.w3.org/TR/xinclude/#include_element\n\nChangelog\n=========\n\ndefusedxml 0.7.1\n---------------------\n\n*Release date: 08-Mar-2021*\n\n- Fix regression ``defusedxml.ElementTree.ParseError`` (#63)\n The ``ParseError`` exception is now the same class object as\n ``xml.etree.ElementTree.ParseError`` again.\n\n\ndefusedxml 0.7.0\n----------------\n\n*Release date: 4-Mar-2021*\n\n- No changes\n\n\ndefusedxml 0.7.0rc2\n-------------------\n\n*Release date: 12-Jan-2021*\n\n- Re-add and deprecate ``defusedxml.cElementTree``\n- Use GitHub Actions instead of TravisCI\n- Restore ``ElementTree`` attribute of ``xml.etree`` module after patching\n\ndefusedxml 0.7.0rc1\n-------------------\n\n*Release date: 04-May-2020*\n\n- Add support for Python 3.9\n- ``defusedxml.cElementTree`` is not available with Python 3.9.\n- Python 2 is deprecate. Support for Python 2 will be removed in 0.8.0.\n\n\ndefusedxml 0.6.0\n----------------\n\n*Release date: 17-Apr-2019*\n\n- Increase test coverage.\n- Add badges to README.\n\n\ndefusedxml 0.6.0rc1\n-------------------\n\n*Release date: 14-Apr-2019*\n\n- Test on Python 3.7 stable and 3.8-dev\n- Drop support for Python 3.4\n- No longer pass *html* argument to XMLParse. It has been deprecated and\n ignored for a long time. The DefusedXMLParser still takes a html argument.\n A deprecation warning is issued when the argument is False and a TypeError\n when it's True.\n- defusedxml now fails early when pyexpat stdlib module is not available or\n broken.\n- defusedxml.ElementTree.__all__ now lists ParseError as public attribute.\n- The defusedxml.ElementTree and defusedxml.cElementTree modules had a typo\n and used XMLParse instead of XMLParser as an alias for DefusedXMLParser.\n Both the old and fixed name are now available.\n\n\ndefusedxml 0.5.0\n----------------\n\n*Release date: 07-Feb-2017*\n\n- No changes\n\n\ndefusedxml 0.5.0.rc1\n--------------------\n\n*Release date: 28-Jan-2017*\n\n- Add compatibility with Python 3.6\n- Drop support for Python 2.6, 3.1, 3.2, 3.3\n- Fix lxml tests (XMLSyntaxError: Detected an entity reference loop)\n\n\ndefusedxml 0.4.1\n----------------\n\n*Release date: 28-Mar-2013*\n\n- Add more demo exploits, e.g. python_external.py and Xalan XSLT demos.\n- Improved documentation.\n\n\ndefusedxml 0.4\n--------------\n\n*Release date: 25-Feb-2013*\n\n- As per http://seclists.org/oss-sec/2013/q1/340 please REJECT\n CVE-2013-0278, CVE-2013-0279 and CVE-2013-0280 and use CVE-2013-1664,\n CVE-2013-1665 for OpenStack/etc.\n- Add missing parser_list argument to sax.make_parser(). The argument is\n ignored, though. (thanks to Florian Apolloner)\n- Add demo exploit for external entity attack on Python's SAX parser, XML-RPC\n and WebDAV.\n\n\ndefusedxml 0.3\n--------------\n\n*Release date: 19-Feb-2013*\n\n- Improve documentation\n\n\ndefusedxml 0.2\n--------------\n\n*Release date: 15-Feb-2013*\n\n- Rename ExternalEntitiesForbidden to ExternalReferenceForbidden\n- Rename defusedxml.lxml.check_dtd() to check_docinfo()\n- Unify argument names in callbacks\n- Add arguments and formatted representation to exceptions\n- Add forbid_external argument to all functions and classes\n- More tests\n- LOTS of documentation\n- Add example code for other languages (Ruby, Perl, PHP) and parsers (Genshi)\n- Add protection against XML and gzip attacks to xmlrpclib\n\ndefusedxml 0.1\n--------------\n\n*Release date: 08-Feb-2013*\n\n- Initial and internal release for PSRT review\n\n\n", + "keywords": [ + "xml", + "bomb", + "DoS" + ], + "home_page": "https://github.com/tiran/defusedxml", + "download_url": "https://pypi.python.org/pypi/defusedxml", + "author": "Christian Heimes", + "author_email": "christian@python.org", + "maintainer": "Christian Heimes", + "maintainer_email": "christian@python.org", + "license": "PSFL", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Python Software Foundation License", + "Natural Language :: English", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Topic :: Text Processing :: Markup :: XML" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", + "hashes": { + "sha256": "841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "jupyterlab_pygments", + "version": "0.3.0", + "summary": "Pygments theme using JupyterLab CSS variables", + "description": "# JupyterLab Pygments Theme\n\nThis package contains a syntax coloring theme for [pygments](http://pygments.org/) making use of\nthe JupyterLab CSS variables.\n\nThe goal is to enable the use of JupyterLab's themes with pygments-generated HTML.\n\n## Screencast\n\nIn the following screencast, we demonstrate how Pygments-highlighted code can make use of the JupyterLab theme.\n\n![pygments screencast](pygments.gif)\n\n## Installation\n\n`jupyterlab_pygments` can be installed with the conda package manager\n\n```\nconda install -c conda-forge jupyterlab_pygments\n```\n\nor from pypi\n\n```\npip install jupyterlab_pygments\n```\n\n## Dependencies\n\n- `jupyterlab_pygments` requires [pygments](http://pygments.org) version `2.4.1`.\n- The CSS variables used by the theme correspond to the CodeMirror syntex coloring\n theme defined in the NPM package [@jupyterlab/codemirror](https://www.npmjs.com/package/@jupyterlab/codemirror). Supported versions for `@jupyterlab/codemirror`'s CSS include `0.19.1`, `^1.0`, and, `^2.0`.\n\n## Limitations\n\nPygments-generated HTML and CSS classes are not granular enough to reproduce\nall of the details of codemirror (the JavaScript text editor used by JupyterLab).\n\nThis includes the ability to differentiate properties from general names.\n\n## License\n\n`jupyterlab_pygments` uses a shared copyright model that enables all contributors to maintain the\ncopyright on their contributions. All code is licensed under the terms of the revised [BSD license](LICENSE).\n", + "description_content_type": "text/markdown", + "author_email": "Jupyter Development Team ", + "license": "Copyright (c) 2015 Project Jupyter Contributors\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "classifier": [ + "Framework :: Jupyter", + "Framework :: Jupyter :: JupyterLab", + "Framework :: Jupyter :: JupyterLab :: 4", + "Framework :: Jupyter :: JupyterLab :: Extensions", + "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://github.com/jupyterlab/jupyterlab_pygments", + "Bug Tracker, https://github.com/jupyterlab/jupyterlab_pygments/issues", + "Repository, https://github.com/jupyterlab/jupyterlab_pygments.git" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", + "hashes": { + "sha256": "24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "rfc3339-validator", + "version": "0.1.4", + "platform": [ + "UNKNOWN" + ], + "summary": "A pure python RFC3339 validator", + "description": "# rfc3339-validator\n\nA pure python RFC3339 validator\n\n\n[![image](https://img.shields.io/pypi/v/rfc3339_validator.svg)](https://pypi.python.org/pypi/rfc3339_validator)\n[![Build Status](https://travis-ci.org/naimetti/rfc3339-validator.svg?branch=master)](https://travis-ci.org/naimetti/rfc3339-validator)\n\n# Install\n\n```shell script\npip install rfc3339-validator\n```\n\n# Usage\n\n```python\nfrom rfc3339_validator import validate_rfc3339\n\nvalidate_rfc3339('1424-45-93T15:32:12.9023368Z')\n>>> False\n\nvalidate_rfc3339('2001-10-23T15:32:12.9023368Z')\n>>> True\n```\n\n\n - Free software: MIT license\n\n\n", + "description_content_type": "text/markdown", + "keywords": [ + "rfc3339", + "validator" + ], + "home_page": "https://github.com/naimetti/rfc3339-validator", + "author": "Nicolas Aimetti", + "author_email": "naimetti@yahoo.com.ar", + "license": "MIT license", + "classifier": [ + "Development Status :: 2 - Pre-Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8" + ], + "requires_dist": [ + "six" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", + "archive_info": { + "hash": "sha256=d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", + "hashes": { + "sha256": "d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "stack-data", + "version": "0.6.3", + "summary": "Extract data from python stack frames and tracebacks for informative displays", + "description": "# stack_data\n\n[![Tests](https://github.com/alexmojaki/stack_data/actions/workflows/pytest.yml/badge.svg)](https://github.com/alexmojaki/stack_data/actions/workflows/pytest.yml) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/stack_data/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/stack_data?branch=master) [![Supports Python versions 3.5+](https://img.shields.io/pypi/pyversions/stack_data.svg)](https://pypi.python.org/pypi/stack_data)\n\nThis is a library that extracts data from stack frames and tracebacks, particularly to display more useful tracebacks than the default. It powers the tracebacks in IPython and [futurecoder](https://futurecoder.io/):\n\n![futurecoder example](https://futurecoder.io/static/img/features/traceback.png)\n\nYou can install it from PyPI:\n\n pip install stack_data\n \n## Basic usage\n\nHere's some code we'd like to inspect:\n\n```python\ndef foo():\n result = []\n for i in range(5):\n row = []\n result.append(row)\n print_stack()\n for j in range(5):\n row.append(i * j)\n return result\n```\n\nNote that `foo` calls a function `print_stack()`. In reality we can imagine that an exception was raised at this line, or a debugger stopped there, but this is easy to play with directly. Here's a basic implementation:\n\n```python\nimport inspect\nimport stack_data\n\n\ndef print_stack():\n frame = inspect.currentframe().f_back\n frame_info = stack_data.FrameInfo(frame)\n print(f\"{frame_info.code.co_name} at line {frame_info.lineno}\")\n print(\"-----------\")\n for line in frame_info.lines:\n print(f\"{'-->' if line.is_current else ' '} {line.lineno:4} | {line.render()}\")\n```\n\n(Beware that this has a major bug - it doesn't account for line gaps, which we'll learn about later)\n\nThe output of one call to `print_stack()` looks like:\n\n```\nfoo at line 9\n-----------\n 6 | for i in range(5):\n 7 | row = []\n 8 | result.append(row)\n--> 9 | print_stack()\n 10 | for j in range(5):\n```\n\nThe code for `print_stack()` is fairly self-explanatory. If you want to learn more details about a particular class or method I suggest looking through some docstrings. `FrameInfo` is a class that accepts either a frame or a traceback object and provides a bunch of nice attributes and properties (which are cached so you don't need to worry about performance). In particular `frame_info.lines` is a list of `Line` objects. `line.render()` returns the source code of that line suitable for display. Without any arguments it simply strips any common leading indentation. Later on we'll see a more powerful use for it.\n\nYou can see that `frame_info.lines` includes some lines of surrounding context. By default it includes 3 pieces of context before the main line and 1 piece after. We can configure the amount of context by passing options:\n\n```python\noptions = stack_data.Options(before=1, after=0)\nframe_info = stack_data.FrameInfo(frame, options)\n```\n\nThen the output looks like:\n\n```\nfoo at line 9\n-----------\n 8 | result.append(row)\n--> 9 | print_stack()\n```\n\nNote that these parameters are not the number of *lines* before and after to include, but the number of *pieces*. A piece is a range of one or more lines in a file that should logically be grouped together. A piece contains either a single simple statement or a part of a compound statement (loops, if, try/except, etc) that doesn't contain any other statements. Most pieces are a single line, but a multi-line statement or `if` condition is a single piece. In the example above, all pieces are one line, because nothing is spread across multiple lines. If we change our code to include some multiline bits:\n\n\n```python\ndef foo():\n result = []\n for i in range(5):\n row = []\n result.append(\n row\n )\n print_stack()\n for j in range(\n 5\n ):\n row.append(i * j)\n return result\n```\n\nand then run the original code with the default options, then the output is:\n\n```\nfoo at line 11\n-----------\n 6 | for i in range(5):\n 7 | row = []\n 8 | result.append(\n 9 | row\n 10 | )\n--> 11 | print_stack()\n 12 | for j in range(\n 13 | 5\n 14 | ):\n```\n\nNow lines 8-10 and lines 12-14 are each a single piece. Note that the output is essentially the same as the original in terms of the amount of code. The division of files into pieces means that the edge of the context is intuitive and doesn't crop out parts of statements or expressions. For example, if context was measured in lines instead of pieces, the last line of the above would be `for j in range(` which is much less useful.\n\nHowever, if a piece is very long, including all of it could be cumbersome. For this, `Options` has a parameter `max_lines_per_piece`, which is 6 by default. Suppose we have a piece in our code that's longer than that:\n\n```python\n row = [\n 1,\n 2,\n 3,\n 4,\n 5,\n ]\n```\n\n`frame_info.lines` will truncate this piece so that instead of 7 `Line` objects it will produce 5 `Line` objects and one `LINE_GAP` in the middle, making 6 objects in total for the piece. Our code doesn't currently handle gaps, so it will raise an exception. We can modify it like so:\n\n```python\n for line in frame_info.lines:\n if line is stack_data.LINE_GAP:\n print(\" (...)\")\n else:\n print(f\"{'-->' if line.is_current else ' '} {line.lineno:4} | {line.render()}\")\n```\n\nNow the output looks like:\n\n```\nfoo at line 15\n-----------\n 6 | for i in range(5):\n 7 | row = [\n 8 | 1,\n 9 | 2,\n (...)\n 12 | 5,\n 13 | ]\n 14 | result.append(row)\n--> 15 | print_stack()\n 16 | for j in range(5):\n```\n\nAlternatively, you can flip the condition around and check `if isinstance(line, stack_data.Line):`. Either way, you should always check for line gaps, or your code may appear to work at first but fail when it encounters a long piece.\n\nNote that the executing piece, i.e. the piece containing the current line being executed (line 15 in this case) is never truncated, no matter how long it is.\n\nThe lines of context never stray outside `frame_info.scope`, which is the innermost function or class definition containing the current line. For example, this is the output for a short function which has neither 3 lines before nor 1 line after the current line:\n\n```\nbar at line 6\n-----------\n 4 | def bar():\n 5 | foo()\n--> 6 | print_stack()\n```\n\nSometimes it's nice to ensure that the function signature is always showing. This can be done with `Options(include_signature=True)`. The result looks like this:\n\n```\nfoo at line 14\n-----------\n 9 | def foo():\n (...)\n 11 | for i in range(5):\n 12 | row = []\n 13 | result.append(row)\n--> 14 | print_stack()\n 15 | for j in range(5):\n```\n\nTo avoid wasting space, pieces never start or end with a blank line, and blank lines between pieces are excluded. So if our code looks like this:\n\n\n```python\n for i in range(5):\n row = []\n\n result.append(row)\n print_stack()\n\n for j in range(5):\n```\n\nThe output doesn't change much, except you can see jumps in the line numbers:\n\n```\n 11 | for i in range(5):\n 12 | row = []\n 14 | result.append(row)\n--> 15 | print_stack()\n 17 | for j in range(5):\n```\n\n## Variables\n\nYou can also inspect variables and other expressions in a frame, e.g:\n\n```python\n for var in frame_info.variables:\n print(f\"{var.name} = {repr(var.value)}\")\n```\n\nwhich may output:\n\n```python\nresult = [[0, 0, 0, 0, 0], [0, 1, 2, 3, 4], [0, 2, 4, 6, 8], [0, 3, 6, 9, 12], []]\ni = 4\nrow = []\nj = 4\n```\n\n`frame_info.variables` returns a list of `Variable` objects, which have attributes `name`, `value`, and `nodes`, which is a list of all AST representing that expression.\n\nA `Variable` may refer to an expression other than a simple variable name. It can be any expression evaluated by the library [`pure_eval`](https://github.com/alexmojaki/pure_eval) which it deems 'interesting' (see those docs for more info). This includes expressions like `foo.bar` or `foo[bar]`. In these cases `name` is the source code of that expression. `pure_eval` ensures that it only evaluates expressions that won't have any side effects, e.g. where `foo.bar` is a normal attribute rather than a descriptor such as a property.\n\n`frame_info.variables` is a list of all the interesting expressions found in `frame_info.scope`, e.g. the current function, which may include expressions not visible in `frame_info.lines`. You can restrict the list by using `frame_info.variables_in_lines` or even `frame_info.variables_in_executing_piece`. For more control you can use `frame_info.variables_by_lineno`. See the docstrings for more information.\n\n## Rendering lines with ranges and markers\n\nSometimes you may want to insert special characters into the text for display purposes, e.g. HTML or ANSI color codes. `stack_data` provides a few tools to make this easier.\n\nLet's say we have a `Line` object where `line.text` (the original raw source code of that line) is `\"foo = bar\"`, so `line.text[6:9]` is `\"bar\"`, and we want to emphasise that part by inserting HTML at positions 6 and 9 in the text. Here's how we can do that directly:\n\n```python\nmarkers = [\n stack_data.MarkerInLine(position=6, is_start=True, string=\"\"),\n stack_data.MarkerInLine(position=9, is_start=False, string=\"\"),\n]\nline.render(markers) # returns \"foo = bar\"\n```\n\nHere `is_start=True` indicates that the marker is the first of a pair. This helps `line.render()` sort and insert the markers correctly so you don't end up with malformed HTML like `foo.bar` where tags overlap.\n\nSince we're inserting HTML, we should actually use `line.render(markers, escape_html=True)` which will escape special HTML characters in the Python source (but not the markers) so for example `foo = bar < spam` would be rendered as `foo = bar < spam`.\n\nUsually though you wouldn't create markers directly yourself. Instead you would start with one or more ranges and then convert them, like so:\n\n```python\nranges = [\n stack_data.RangeInLine(start=0, end=3, data=\"foo\"),\n stack_data.RangeInLine(start=6, end=9, data=\"bar\"),\n]\n\ndef convert_ranges(r):\n if r.data == \"bar\":\n return \"\", \"\" \n\n# This results in `markers` being the same as in the above example.\nmarkers = stack_data.markers_from_ranges(ranges, convert_ranges)\n```\n\n`RangeInLine` has a `data` attribute which can be any object. `markers_from_ranges` accepts a converter function to which it passes all the `RangeInLine` objects. If the converter function returns a pair of strings, it creates two markers from them. Otherwise it should return `None` to indicate that the range should be ignored, as with the first range containing `\"foo\"` in this example.\n\nThe reason this is useful is because there are built in tools to create these ranges for you. For example, if we change our `print_stack()` function to contain this:\n\n```python\ndef convert_variable_ranges(r):\n variable, _node = r.data\n return f'', ''\n\nmarkers = stack_data.markers_from_ranges(line.variable_ranges, convert_variable_ranges)\nprint(f\"{'-->' if line.is_current else ' '} {line.lineno:4} | {line.render(markers, escape_html=True)}\")\n```\n\nThen the output becomes:\n\n```\nfoo at line 15\n-----------\n 9 | def foo():\n (...)\n 11 | for i in range(5):\n 12 | row = []\n 14 | result.append(row)\n--> 15 | print_stack()\n 17 | for j in range(5):\n```\n\n`line.variable_ranges` is a list of RangeInLines for each Variable that appears at least partially in this line. The data attribute of the range is a pair `(variable, node)` where node is the particular AST node from the list `variable.nodes` that corresponds to this range.\n\nYou can also use `line.token_ranges` (e.g. if you want to do your own syntax highlighting) or `line.executing_node_ranges` if you want to highlight the currently executing node identified by the [`executing`](https://github.com/alexmojaki/executing) library. Or if you want to make your own range from an AST node, use `line.range_from_node(node, data)`. See the docstrings for more info.\n\n### Syntax highlighting with Pygments\n\nIf you'd like pretty colored text without the work, you can let [Pygments](https://pygments.org/) do it for you. Just follow these steps:\n\n1. `pip install pygments` separately as it's not a dependency of `stack_data`.\n2. Create a pygments formatter object such as `HtmlFormatter` or `Terminal256Formatter`.\n3. Pass the formatter to `Options` in the argument `pygments_formatter`.\n4. Use `line.render(pygmented=True)` to get your formatted text. In this case you can't pass any markers to `render`.\n\nIf you want, you can also highlight the executing node in the frame in combination with the pygments syntax highlighting. For this you will need:\n\n1. A pygments style - either a style class or a string that names it. See the [documentation on styles](https://pygments.org/docs/styles/) and the [styles gallery](https://blog.yjl.im/2015/08/pygments-styles-gallery.html).\n2. A modification to make to the style for the executing node, which is a string such as `\"bold\"` or `\"bg:#ffff00\"` (yellow background). See the [documentation on style rules](https://pygments.org/docs/styles/#style-rules).\n3. Pass these two things to `stack_data.style_with_executing_node(style, modifier)` to get a new style class.\n4. Pass the new style to your formatter when you create it.\n\nNote that this doesn't work with `TerminalFormatter` which just uses the basic ANSI colors and doesn't use the style passed to it in general.\n\n## Getting the full stack\n\nCurrently `print_stack()` doesn't actually print the stack, it just prints one frame. Instead of `frame_info = FrameInfo(frame, options)`, let's do this:\n\n```python\nfor frame_info in FrameInfo.stack_data(frame, options):\n```\n\nNow the output looks something like this:\n\n```\n at line 18\n-----------\n 14 | for j in range(5):\n 15 | row.append(i * j)\n 16 | return result\n--> 18 | bar()\n\nbar at line 5\n-----------\n 4 | def bar():\n--> 5 | foo()\n\nfoo at line 13\n-----------\n 10 | for i in range(5):\n 11 | row = []\n 12 | result.append(row)\n--> 13 | print_stack()\n 14 | for j in range(5):\n```\n\nHowever, just as `frame_info.lines` doesn't always yield `Line` objects, `FrameInfo.stack_data` doesn't always yield `FrameInfo` objects, and we must modify our code to handle that. Let's look at some different sample code:\n\n```python\ndef factorial(x):\n return x * factorial(x - 1)\n\n\ntry:\n print(factorial(5))\nexcept:\n print_stack()\n```\n\nIn this code we've forgotten to include a base case in our `factorial` function so it will fail with a `RecursionError` and there'll be many frames with similar information. Similar to the built in Python traceback, `stack_data` avoids showing all of these frames. Instead you will get a `RepeatedFrames` object which summarises the information. See its docstring for more details.\n\nHere is our updated implementation:\n\n```python\ndef print_stack():\n for frame_info in FrameInfo.stack_data(sys.exc_info()[2]):\n if isinstance(frame_info, FrameInfo):\n print(f\"{frame_info.code.co_name} at line {frame_info.lineno}\")\n print(\"-----------\")\n for line in frame_info.lines:\n print(f\"{'-->' if line.is_current else ' '} {line.lineno:4} | {line.render()}\")\n\n for var in frame_info.variables:\n print(f\"{var.name} = {repr(var.value)}\")\n\n print()\n else:\n print(f\"... {frame_info.description} ...\\n\")\n```\n\nAnd the output:\n\n```\n at line 9\n-----------\n 4 | def factorial(x):\n 5 | return x * factorial(x - 1)\n 8 | try:\n--> 9 | print(factorial(5))\n 10 | except:\n\nfactorial at line 5\n-----------\n 4 | def factorial(x):\n--> 5 | return x * factorial(x - 1)\nx = 5\n\nfactorial at line 5\n-----------\n 4 | def factorial(x):\n--> 5 | return x * factorial(x - 1)\nx = 4\n\n... factorial at line 5 (996 times) ...\n\nfactorial at line 5\n-----------\n 4 | def factorial(x):\n--> 5 | return x * factorial(x - 1)\nx = -993\n```\n\nIn addition to handling repeated frames, we've passed a traceback object to `FrameInfo.stack_data` instead of a frame.\n\nIf you want, you can pass `collapse_repeated_frames=False` to `FrameInfo.stack_data` (not to `Options`) and it will just yield `FrameInfo` objects for the full stack.\n", + "description_content_type": "text/markdown", + "home_page": "http://github.com/alexmojaki/stack_data", + "author": "Alex Hall", + "author_email": "alex.mojaki@gmail.com", + "license": "MIT", + "classifier": [ + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Topic :: Software Development :: Debuggers" + ], + "requires_dist": [ + "executing >=1.2.0", + "asttokens >=2.1.0", + "pure-eval", + "pytest ; extra == 'tests'", + "typeguard ; extra == 'tests'", + "pygments ; extra == 'tests'", + "littleutils ; extra == 'tests'", + "cython ; extra == 'tests'" + ], + "provides_extra": [ + "tests" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/2c/4d/0db5b8a613d2a59bbc29bc5bb44a2f8070eb9ceab11c50d477502a8a0092/tinycss2-1.3.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7", + "hashes": { + "sha256": "54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "tinycss2", + "version": "1.3.0", + "summary": "A tiny CSS parser", + "description": "tinycss2 is a low-level CSS parser and generator written in Python: it can\nparse strings, return objects representing tokens and blocks, and generate CSS\nstrings corresponding to these objects.\n\nBased on the CSS Syntax Level 3 specification, tinycss2 knows the grammar of\nCSS but doesn't know specific rules, properties or values supported in various\nCSS modules.\n\n* Free software: BSD license\n* For Python 3.8+, tested on CPython and PyPy\n* Documentation: https://doc.courtbouillon.org/tinycss2\n* Changelog: https://github.com/Kozea/tinycss2/releases\n* Code, issues, tests: https://github.com/Kozea/tinycss2\n* Code of conduct: https://www.courtbouillon.org/code-of-conduct\n* Professional support: https://www.courtbouillon.org\n* Donation: https://opencollective.com/courtbouillon\n\ntinycss2 has been created and developed by Kozea (https://kozea.fr).\nProfessional support, maintenance and community management is provided by\nCourtBouillon (https://www.courtbouillon.org).\n\nCopyrights are retained by their contributors, no copyright assignment is\nrequired to contribute to tinycss2. Unless explicitly stated otherwise, any\ncontribution intentionally submitted for inclusion is licensed under the BSD\n3-clause license, without any additional terms or conditions. For full\nauthorship information, see the version control history.\n\n", + "description_content_type": "text/x-rst", + "keywords": [ + "css", + "parser" + ], + "author_email": "Simon Sapin ", + "maintainer_email": "CourtBouillon ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Text Processing" + ], + "requires_dist": [ + "webencodings >=0.4", + "sphinx ; extra == \"doc\"", + "sphinx_rtd_theme ; extra == \"doc\"", + "pytest ; extra == \"test\"", + "ruff ; extra == \"test\"" + ], + "requires_python": ">=3.8", + "project_url": [ + "Changelog, https://github.com/Kozea/tinycss2/releases", + "Code, https://github.com/Kozea/tinycss2/", + "Documentation, https://doc.courtbouillon.org/tinycss2/", + "Donation, https://opencollective.com/courtbouillon", + "Homepage, https://www.courtbouillon.org/tinycss2", + "Issues, https://github.com/Kozea/tinycss2/issues" + ], + "provides_extra": [ + "doc", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/45/86/4736ac618d82a20d87d2f92ae19441ebc7ac9e7a581d7e58bbe79233b24a/asttokens-2.4.1-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", + "hashes": { + "sha256": "051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "asttokens", + "version": "2.4.1", + "summary": "Annotate AST trees with source code positions", + "description": "ASTTokens\n=========\n\n.. image:: https://img.shields.io/pypi/v/asttokens.svg\n :target: https://pypi.python.org/pypi/asttokens/\n.. image:: https://img.shields.io/pypi/pyversions/asttokens.svg\n :target: https://pypi.python.org/pypi/asttokens/\n.. image:: https://github.com/gristlabs/asttokens/actions/workflows/build-and-test.yml/badge.svg\n :target: https://github.com/gristlabs/asttokens/actions/workflows/build-and-test.yml\n.. image:: https://readthedocs.org/projects/asttokens/badge/?version=latest\n :target: http://asttokens.readthedocs.io/en/latest/index.html\n.. image:: https://coveralls.io/repos/github/gristlabs/asttokens/badge.svg\n :target: https://coveralls.io/github/gristlabs/asttokens\n\n.. Start of user-guide\n\nThe ``asttokens`` module annotates Python abstract syntax trees (ASTs) with the positions of tokens\nand text in the source code that generated them.\n\nIt makes it possible for tools that work with logical AST nodes to find the particular text that\nresulted in those nodes, for example for automated refactoring or highlighting.\n\nInstallation\n------------\nasttokens is available on PyPI: https://pypi.python.org/pypi/asttokens/::\n\n pip install asttokens\n\nThe code is on GitHub: https://github.com/gristlabs/asttokens.\n\nThe API Reference is here: http://asttokens.readthedocs.io/en/latest/api-index.html.\n\nUsage\n-----\nASTTokens works with both Python2 and Python3.\n\nASTTokens can annotate both trees built by `ast `_,\nAND those built by `astroid `_.\n\nHere's an example:\n\n.. code-block:: python\n\n import asttokens, ast\n source = \"Robot('blue').walk(steps=10*n)\"\n atok = asttokens.ASTTokens(source, parse=True)\n\nOnce the tree has been marked, nodes get ``.first_token``, ``.last_token`` attributes, and\nthe ``ASTTokens`` object offers helpful methods:\n\n.. code-block:: python\n\n attr_node = next(n for n in ast.walk(atok.tree) if isinstance(n, ast.Attribute))\n print(atok.get_text(attr_node))\n start, end = attr_node.last_token.startpos, attr_node.last_token.endpos\n print(atok.text[:start] + 'RUN' + atok.text[end:])\n\nWhich produces this output:\n\n.. code-block:: text\n\n Robot('blue').walk\n Robot('blue').RUN(steps=10*n)\n\nThe ``ASTTokens`` object also offers methods to walk and search the list of tokens that make up\nthe code (or a particular AST node), which is more useful and powerful than dealing with the text\ndirectly.\n\n\nContribute\n----------\n\nTo contribute:\n\n1. Fork this repository, and clone your fork.\n2. Install the package with test dependencies (ideally in a virtualenv) with::\n\n pip install -e '.[test]'\n\n3. Run tests in your current interpreter with the command ``pytest`` or ``python -m pytest``.\n4. Run tests across all supported interpreters with the ``tox`` command. You will need to have the interpreters installed separately. We recommend ``pyenv`` for that. Use ``tox -p auto`` to run the tests in parallel.\n5. By default certain tests which take a very long time to run are skipped, but they are run on travis CI. To run them locally, set the environment variable ``ASTTOKENS_SLOW_TESTS``. For example run ``ASTTOKENS_SLOW_TESTS=1 tox`` to run the full suite of tests.\n", + "keywords": [ + "code", + "ast", + "parse", + "tokenize", + "refactor" + ], + "home_page": "https://github.com/gristlabs/asttokens", + "author": "Dmitry Sagalovskiy, Grist Labs", + "author_email": "dmitry@getgrist.com", + "license": "Apache 2.0", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Code Generators", + "Topic :: Software Development :: Compilers", + "Topic :: Software Development :: Interpreters", + "Topic :: Software Development :: Pre-processors", + "Environment :: Console", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy" + ], + "requires_dist": [ + "six >=1.12.0", + "typing ; python_version < \"3.5\"", + "astroid <2,>=1 ; (python_version < \"3\") and extra == 'astroid'", + "astroid <4,>=2 ; (python_version >= \"3\") and extra == 'astroid'", + "pytest ; extra == 'test'", + "astroid <2,>=1 ; (python_version < \"3\") and extra == 'test'", + "astroid <4,>=2 ; (python_version >= \"3\") and extra == 'test'" + ], + "provides_extra": [ + "astroid", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/e9/63/e285470a4880a4f36edabe4810057bd4b562c6ddcc165eacf9c3c7210b40/cffi-1.16.0-cp312-cp312-win_amd64.whl", + "archive_info": { + "hash": "sha256=68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", + "hashes": { + "sha256": "68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "cffi", + "version": "1.16.0", + "summary": "Foreign Function Interface for Python calling C code.", + "description": "\r\nCFFI\r\n====\r\n\r\nForeign Function Interface for Python calling C code.\r\nPlease see the `Documentation `_.\r\n\r\nContact\r\n-------\r\n\r\n`Mailing list `_\r\n", + "home_page": "http://cffi.readthedocs.org", + "author": "Armin Rigo, Maciej Fijalkowski", + "author_email": "python-cffi@googlegroups.com", + "license": "MIT", + "classifier": [ + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "License :: OSI Approved :: MIT License" + ], + "requires_dist": [ + "pycparser" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, http://cffi.readthedocs.org/", + "Source Code, https://github.com/python-cffi/cffi", + "Issue Tracker, https://github.com/python-cffi/cffi/issues", + "Changelog, https://cffi.readthedocs.io/en/latest/whatsnew.html", + "Downloads, https://github.com/python-cffi/cffi/releases", + "Contact, https://groups.google.com/forum/#!forum/python-cffi" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/80/03/6ea8b1b2a5ab40a7a60dc464d3daa7aa546e0a74d74a9f8ff551ea7905db/executing-2.0.1-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc", + "hashes": { + "sha256": "eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "executing", + "version": "2.0.1", + "summary": "Get the currently executing AST node of a frame, and other information", + "description": "# executing\n\n[![Build Status](https://github.com/alexmojaki/executing/workflows/Tests/badge.svg?branch=master)](https://github.com/alexmojaki/executing/actions) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/executing/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/executing?branch=master) [![Supports Python versions 3.5+, including PyPy](https://img.shields.io/pypi/pyversions/executing.svg)](https://pypi.python.org/pypi/executing)\n\nThis mini-package lets you get information about what a frame is currently doing, particularly the AST node being executed.\n\n* [Usage](#usage)\n * [Getting the AST node](#getting-the-ast-node)\n * [Getting the source code of the node](#getting-the-source-code-of-the-node)\n * [Getting the `__qualname__` of the current function](#getting-the-__qualname__-of-the-current-function)\n * [The Source class](#the-source-class)\n* [Installation](#installation)\n* [How does it work?](#how-does-it-work)\n* [Is it reliable?](#is-it-reliable)\n* [Which nodes can it identify?](#which-nodes-can-it-identify)\n* [Libraries that use this](#libraries-that-use-this)\n\n## Usage\n\n### Getting the AST node\n\n```python\nimport executing\n\nnode = executing.Source.executing(frame).node\n```\n\nThen `node` will be an AST node (from the `ast` standard library module) or None if the node couldn't be identified (which may happen often and should always be checked).\n\n`node` will always be the same instance for multiple calls with frames at the same point of execution.\n\nIf you have a traceback object, pass it directly to `Source.executing()` rather than the `tb_frame` attribute to get the correct node.\n\n### Getting the source code of the node\n\nFor this you will need to separately install the [`asttokens`](https://github.com/gristlabs/asttokens) library, then obtain an `ASTTokens` object:\n\n```python\nexecuting.Source.executing(frame).source.asttokens()\n```\n\nor:\n\n```python\nexecuting.Source.for_frame(frame).asttokens()\n```\n\nor use one of the convenience methods:\n\n```python\nexecuting.Source.executing(frame).text()\nexecuting.Source.executing(frame).text_range()\n```\n\n### Getting the `__qualname__` of the current function\n\n```python\nexecuting.Source.executing(frame).code_qualname()\n```\n\nor:\n\n```python\nexecuting.Source.for_frame(frame).code_qualname(frame.f_code)\n```\n\n### The `Source` class\n\nEverything goes through the `Source` class. Only one instance of the class is created for each filename. Subclassing it to add more attributes on creation or methods is recommended. The classmethods such as `executing` will respect this. See the source code and docstrings for more detail.\n\n## Installation\n\n pip install executing\n\nIf you don't like that you can just copy the file `executing.py`, there are no dependencies (but of course you won't get updates).\n\n## How does it work?\n\nSuppose the frame is executing this line:\n\n```python\nself.foo(bar.x)\n```\n\nand in particular it's currently obtaining the attribute `self.foo`. Looking at the bytecode, specifically `frame.f_code.co_code[frame.f_lasti]`, we can tell that it's loading an attribute, but it's not obvious which one. We can narrow down the statement being executed using `frame.f_lineno` and find the two `ast.Attribute` nodes representing `self.foo` and `bar.x`. How do we find out which one it is, without recreating the entire compiler in Python?\n\nThe trick is to modify the AST slightly for each candidate expression and observe the changes in the bytecode instructions. We change the AST to this:\n\n```python\n(self.foo ** 'longuniqueconstant')(bar.x)\n```\n \nand compile it, and the bytecode will be almost the same but there will be two new instructions:\n\n LOAD_CONST 'longuniqueconstant'\n BINARY_POWER\n\nand just before that will be a `LOAD_ATTR` instruction corresponding to `self.foo`. Seeing that it's in the same position as the original instruction lets us know we've found our match.\n\n## Is it reliable?\n\nYes - if it identifies a node, you can trust that it's identified the correct one. The tests are very thorough - in addition to unit tests which check various situations directly, there are property tests against a large number of files (see the filenames printed in [this build](https://travis-ci.org/alexmojaki/executing/jobs/557970457)) with real code. Specifically, for each file, the tests:\n \n 1. Identify as many nodes as possible from all the bytecode instructions in the file, and assert that they are all distinct\n 2. Find all the nodes that should be identifiable, and assert that they were indeed identified somewhere\n\nIn other words, it shows that there is a one-to-one mapping between the nodes and the instructions that can be handled. This leaves very little room for a bug to creep in.\n\nFurthermore, `executing` checks that the instructions compiled from the modified AST exactly match the original code save for a few small known exceptions. This accounts for all the quirks and optimisations in the interpreter. \n\n## Which nodes can it identify?\n\nCurrently it works in almost all cases for the following `ast` nodes:\n \n - `Call`, e.g. `self.foo(bar)`\n - `Attribute`, e.g. `point.x`\n - `Subscript`, e.g. `lst[1]`\n - `BinOp`, e.g. `x + y` (doesn't include `and` and `or`)\n - `UnaryOp`, e.g. `-n` (includes `not` but only works sometimes)\n - `Compare` e.g. `a < b` (not for chains such as `0 < p < 1`)\n\nThe plan is to extend to more operations in the future.\n\n## Projects that use this\n\n### My Projects\n\n- **[`stack_data`](https://github.com/alexmojaki/stack_data)**: Extracts data from stack frames and tracebacks, particularly to display more useful tracebacks than the default. Also uses another related library of mine: **[`pure_eval`](https://github.com/alexmojaki/pure_eval)**.\n- **[`futurecoder`](https://futurecoder.io/)**: Highlights the executing node in tracebacks using `executing` via `stack_data`, and provides debugging with `snoop`.\n- **[`snoop`](https://github.com/alexmojaki/snoop)**: A feature-rich and convenient debugging library. Uses `executing` to show the operation which caused an exception and to allow the `pp` function to display the source of its arguments.\n- **[`heartrate`](https://github.com/alexmojaki/heartrate)**: A simple real time visualisation of the execution of a Python program. Uses `executing` to highlight currently executing operations, particularly in each frame of the stack trace.\n- **[`sorcery`](https://github.com/alexmojaki/sorcery)**: Dark magic delights in Python. Uses `executing` to let special callables called spells know where they're being called from.\n\n### Projects I've contributed to\n\n- **[`IPython`](https://github.com/ipython/ipython/pull/12150)**: Highlights the executing node in tracebacks using `executing` via [`stack_data`](https://github.com/alexmojaki/stack_data).\n- **[`icecream`](https://github.com/gruns/icecream)**: 🍦 Sweet and creamy print debugging. Uses `executing` to identify where `ic` is called and print its arguments.\n- **[`friendly_traceback`](https://github.com/friendly-traceback/friendly-traceback)**: Uses `stack_data` and `executing` to pinpoint the cause of errors and provide helpful explanations.\n- **[`python-devtools`](https://github.com/samuelcolvin/python-devtools)**: Uses `executing` for print debugging similar to `icecream`.\n- **[`sentry_sdk`](https://github.com/getsentry/sentry-python)**: Add the integration `sentry_sdk.integrations.executingExecutingIntegration()` to show the function `__qualname__` in each frame in sentry events.\n- **[`varname`](https://github.com/pwwang/python-varname)**: Dark magics about variable names in python. Uses `executing` to find where its various magical functions like `varname` and `nameof` are called from.\n", + "description_content_type": "text/markdown", + "home_page": "https://github.com/alexmojaki/executing", + "author": "Alex Hall", + "author_email": "alex.mojaki@gmail.com", + "license": "MIT", + "classifier": [ + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" + ], + "requires_dist": [ + "asttokens >=2.1.0 ; extra == 'tests'", + "ipython ; extra == 'tests'", + "pytest ; extra == 'tests'", + "coverage ; extra == 'tests'", + "coverage-enable-subprocess ; extra == 'tests'", + "littleutils ; extra == 'tests'", + "rich ; (python_version >= \"3.11\") and extra == 'tests'" + ], + "requires_python": ">=3.5", + "provides_extra": [ + "tests" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/12/f6/0232cc0c617e195f06f810534d00b74d2f348fe71b2118009ad8ad31f878/jsonpointer-2.4-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a", + "hashes": { + "sha256": "15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "jsonpointer", + "version": "2.4", + "platform": [ + "UNKNOWN" + ], + "summary": "Identify specific nodes in a JSON document (RFC 6901) ", + "description": "python-json-pointer\n===================\n\n[![PyPI version](https://img.shields.io/pypi/v/jsonpointer.svg)](https://pypi.python.org/pypi/jsonpointer/)\n[![Supported Python versions](https://img.shields.io/pypi/pyversions/jsonpointer.svg)](https://pypi.python.org/pypi/jsonpointer/)\n[![Build Status](https://travis-ci.org/stefankoegl/python-json-pointer.svg?branch=master)](https://travis-ci.org/stefankoegl/python-json-pointer)\n[![Coverage Status](https://coveralls.io/repos/stefankoegl/python-json-pointer/badge.svg?branch=master)](https://coveralls.io/r/stefankoegl/python-json-pointer?branch=master)\n\n\nResolve JSON Pointers in Python\n-------------------------------\n\nLibrary to resolve JSON Pointers according to\n[RFC 6901](http://tools.ietf.org/html/rfc6901)\n\nSee source code for examples\n* Website: https://github.com/stefankoegl/python-json-pointer\n* Repository: https://github.com/stefankoegl/python-json-pointer.git\n* Documentation: https://python-json-pointer.readthedocs.org/\n* PyPI: https://pypi.python.org/pypi/jsonpointer\n* Travis CI: https://travis-ci.org/stefankoegl/python-json-pointer\n* Coveralls: https://coveralls.io/r/stefankoegl/python-json-pointer\n\n\n", + "description_content_type": "text/markdown", + "home_page": "https://github.com/stefankoegl/python-json-pointer", + "author": "Stefan Kögl", + "author_email": "stefan@skoegl.net", + "license": "Modified BSD License", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", + "hashes": { + "sha256": "a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "parso", + "version": "0.8.4", + "platform": [ + "any" + ], + "summary": "A Python Parser", + "description": "###################################################################\nparso - A Python Parser\n###################################################################\n\n\n.. image:: https://github.com/davidhalter/parso/workflows/Build/badge.svg?branch=master\n :target: https://github.com/davidhalter/parso/actions\n :alt: GitHub Actions build status\n\n.. image:: https://coveralls.io/repos/github/davidhalter/parso/badge.svg?branch=master\n :target: https://coveralls.io/github/davidhalter/parso?branch=master\n :alt: Coverage Status\n\n.. image:: https://pepy.tech/badge/parso\n :target: https://pepy.tech/project/parso\n :alt: PyPI Downloads\n\n.. image:: https://raw.githubusercontent.com/davidhalter/parso/master/docs/_static/logo_characters.png\n\nParso is a Python parser that supports error recovery and round-trip parsing\nfor different Python versions (in multiple Python versions). Parso is also able\nto list multiple syntax errors in your python file.\n\nParso has been battle-tested by jedi_. It was pulled out of jedi to be useful\nfor other projects as well.\n\nParso consists of a small API to parse Python and analyse the syntax tree.\n\nA simple example:\n\n.. code-block:: python\n\n >>> import parso\n >>> module = parso.parse('hello + 1', version=\"3.9\")\n >>> expr = module.children[0]\n >>> expr\n PythonNode(arith_expr, [, , ])\n >>> print(expr.get_code())\n hello + 1\n >>> name = expr.children[0]\n >>> name\n \n >>> name.end_pos\n (1, 5)\n >>> expr.end_pos\n (1, 9)\n\nTo list multiple issues:\n\n.. code-block:: python\n\n >>> grammar = parso.load_grammar()\n >>> module = grammar.parse('foo +\\nbar\\ncontinue')\n >>> error1, error2 = grammar.iter_errors(module)\n >>> error1.message\n 'SyntaxError: invalid syntax'\n >>> error2.message\n \"SyntaxError: 'continue' not properly in loop\"\n\nResources\n=========\n\n- `Testing `_\n- `PyPI `_\n- `Docs `_\n- Uses `semantic versioning `_\n\nInstallation\n============\n\n pip install parso\n\nFuture\n======\n\n- There will be better support for refactoring and comments. Stay tuned.\n- There's a WIP PEP8 validator. It's however not in a good shape, yet.\n\nKnown Issues\n============\n\n- `async`/`await` are already used as keywords in Python3.6.\n- `from __future__ import print_function` is not ignored.\n\n\nAcknowledgements\n================\n\n- Guido van Rossum (@gvanrossum) for creating the parser generator pgen2\n (originally used in lib2to3).\n- `Salome Schneider `_\n for the extremely awesome parso logo.\n\n\n.. _jedi: https://github.com/davidhalter/jedi\n\n\n.. :changelog:\n\nChangelog\n---------\n\nUnreleased\n++++++++++\n\n0.8.4 (2024-04-05)\n++++++++++++++++++\n\n- Add basic support for Python 3.13\n\n0.8.3 (2021-11-30)\n++++++++++++++++++\n\n- Add basic support for Python 3.11 and 3.12\n\n0.8.2 (2021-03-30)\n++++++++++++++++++\n\n- Various small bugfixes\n\n0.8.1 (2020-12-10)\n++++++++++++++++++\n\n- Various small bugfixes\n\n0.8.0 (2020-08-05)\n++++++++++++++++++\n\n- Dropped Support for Python 2.7, 3.4, 3.5\n- It's possible to use ``pathlib.Path`` objects now in the API\n- The stubs are gone, we are now using annotations\n- ``namedexpr_test`` nodes are now a proper class called ``NamedExpr``\n- A lot of smaller refactorings\n\n0.7.1 (2020-07-24)\n++++++++++++++++++\n\n- Fixed a couple of smaller bugs (mostly syntax error detection in\n ``Grammar.iter_errors``)\n\nThis is going to be the last release that supports Python 2.7, 3.4 and 3.5.\n\n0.7.0 (2020-04-13)\n++++++++++++++++++\n\n- Fix a lot of annoying bugs in the diff parser. The fuzzer did not find\n issues anymore even after running it for more than 24 hours (500k tests).\n- Small grammar change: suites can now contain newlines even after a newline.\n This should really not matter if you don't use error recovery. It allows for\n nicer error recovery.\n\n0.6.2 (2020-02-27)\n++++++++++++++++++\n\n- Bugfixes\n- Add Grammar.refactor (might still be subject to change until 0.7.0)\n\n0.6.1 (2020-02-03)\n++++++++++++++++++\n\n- Add ``parso.normalizer.Issue.end_pos`` to make it possible to know where an\n issue ends\n\n0.6.0 (2020-01-26)\n++++++++++++++++++\n\n- Dropped Python 2.6/Python 3.3 support\n- del_stmt names are now considered as a definition\n (for ``name.is_definition()``)\n- Bugfixes\n\n0.5.2 (2019-12-15)\n++++++++++++++++++\n\n- Add include_setitem to get_definition/is_definition and get_defined_names (#66)\n- Fix named expression error listing (#89, #90)\n- Fix some f-string tokenizer issues (#93)\n\n0.5.1 (2019-07-13)\n++++++++++++++++++\n\n- Fix: Some unicode identifiers were not correctly tokenized\n- Fix: Line continuations in f-strings are now working\n\n0.5.0 (2019-06-20)\n++++++++++++++++++\n\n- **Breaking Change** comp_for is now called sync_comp_for for all Python\n versions to be compatible with the Python 3.8 Grammar\n- Added .pyi stubs for a lot of the parso API\n- Small FileIO changes\n\n0.4.0 (2019-04-05)\n++++++++++++++++++\n\n- Python 3.8 support\n- FileIO support, it's now possible to use abstract file IO, support is alpha\n\n0.3.4 (2019-02-13)\n+++++++++++++++++++\n\n- Fix an f-string tokenizer error\n\n0.3.3 (2019-02-06)\n+++++++++++++++++++\n\n- Fix async errors in the diff parser\n- A fix in iter_errors\n- This is a very small bugfix release\n\n0.3.2 (2019-01-24)\n+++++++++++++++++++\n\n- 20+ bugfixes in the diff parser and 3 in the tokenizer\n- A fuzzer for the diff parser, to give confidence that the diff parser is in a\n good shape.\n- Some bugfixes for f-string\n\n0.3.1 (2018-07-09)\n+++++++++++++++++++\n\n- Bugfixes in the diff parser and keyword-only arguments\n\n0.3.0 (2018-06-30)\n+++++++++++++++++++\n\n- Rewrote the pgen2 parser generator.\n\n0.2.1 (2018-05-21)\n+++++++++++++++++++\n\n- A bugfix for the diff parser.\n- Grammar files can now be loaded from a specific path.\n\n0.2.0 (2018-04-15)\n+++++++++++++++++++\n\n- f-strings are now parsed as a part of the normal Python grammar. This makes\n it way easier to deal with them.\n\n0.1.1 (2017-11-05)\n+++++++++++++++++++\n\n- Fixed a few bugs in the caching layer\n- Added support for Python 3.7\n\n0.1.0 (2017-09-04)\n+++++++++++++++++++\n\n- Pulling the library out of Jedi. Some APIs will definitely change.\n\n\n", + "keywords": [ + "python", + "parser", + "parsing" + ], + "home_page": "https://github.com/davidhalter/parso", + "author": "David Halter", + "author_email": "davidhalter88@gmail.com", + "maintainer": "David Halter", + "maintainer_email": "davidhalter88@gmail.com", + "license": "MIT", + "classifier": [ + "Development Status :: 4 - Beta", + "Environment :: Plugins", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Text Editors :: Integrated Development Environments (IDE)", + "Topic :: Utilities", + "Typing :: Typed" + ], + "requires_dist": [ + "flake8 (==5.0.4) ; extra == 'qa'", + "mypy (==0.971) ; extra == 'qa'", + "types-setuptools (==67.2.0.1) ; extra == 'qa'", + "docopt ; extra == 'testing'", + "pytest ; extra == 'testing'" + ], + "requires_python": ">=3.6", + "provides_extra": [ + "qa", + "testing" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "hashes": { + "sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "six", + "version": "1.16.0", + "platform": [ + "UNKNOWN" + ], + "summary": "Python 2 and 3 compatibility utilities", + "description": ".. image:: https://img.shields.io/pypi/v/six.svg\n :target: https://pypi.org/project/six/\n :alt: six on PyPI\n\n.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master\n :target: https://travis-ci.org/benjaminp/six\n :alt: six on TravisCI\n\n.. image:: https://readthedocs.org/projects/six/badge/?version=latest\n :target: https://six.readthedocs.io/\n :alt: six's documentation on Read the Docs\n\n.. image:: https://img.shields.io/badge/license-MIT-green.svg\n :target: https://github.com/benjaminp/six/blob/master/LICENSE\n :alt: MIT License badge\n\nSix is a Python 2 and 3 compatibility library. It provides utility functions\nfor smoothing over the differences between the Python versions with the goal of\nwriting Python code that is compatible on both Python versions. See the\ndocumentation for more information on what is provided.\n\nSix supports Python 2.7 and 3.3+. It is contained in only one Python\nfile, so it can be easily copied into your project. (The copyright and license\nnotice must be retained.)\n\nOnline documentation is at https://six.readthedocs.io/.\n\nBugs can be reported to https://github.com/benjaminp/six. The code can also\nbe found there.\n\n\n", + "home_page": "https://github.com/benjaminp/six", + "author": "Benjamin Peterson", + "author_email": "benjamin@python.org", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/4c/f3/038b302fdfbe3be7da016777069f26ceefe11a681055ea1f7817546508e3/soupsieve-2.5-py3-none-any.whl", + "archive_info": { + "hash": "sha256=eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7", + "hashes": { + "sha256": "eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "soupsieve", + "version": "2.5", + "summary": "A modern CSS selector implementation for Beautiful Soup.", + "description": "[![Donate via PayPal][donate-image]][donate-link]\n[![Discord][discord-image]][discord-link]\n[![Build][github-ci-image]][github-ci-link]\n[![Coverage Status][codecov-image]][codecov-link]\n[![PyPI Version][pypi-image]][pypi-link]\n[![PyPI Downloads][pypi-down]][pypi-link]\n[![PyPI - Python Version][python-image]][pypi-link]\n![License][license-image-mit]\n\n# Soup Sieve\n\n## Overview\n\nSoup Sieve is a CSS selector library designed to be used with [Beautiful Soup 4][bs4]. It aims to provide selecting,\nmatching, and filtering using modern CSS selectors. Soup Sieve currently provides selectors from the CSS level 1\nspecifications up through the latest CSS level 4 drafts and beyond (though some are not yet implemented).\n\nSoup Sieve was written with the intent to replace Beautiful Soup's builtin select feature, and as of Beautiful Soup\nversion 4.7.0, it now is :confetti_ball:. Soup Sieve can also be imported in order to use its API directly for\nmore controlled, specialized parsing.\n\nSoup Sieve has implemented most of the CSS selectors up through the latest CSS draft specifications, though there are a\nnumber that don't make sense in a non-browser environment. Selectors that cannot provide meaningful functionality simply\ndo not match anything. Some of the supported selectors are:\n\n- `.classes`\n- `#ids`\n- `[attributes=value]`\n- `parent child`\n- `parent > child`\n- `sibling ~ sibling`\n- `sibling + sibling`\n- `:not(element.class, element2.class)`\n- `:is(element.class, element2.class)`\n- `parent:has(> child)`\n- and [many more](https://facelessuser.github.io/soupsieve/selectors/)\n\n\n## Installation\n\nYou must have Beautiful Soup already installed:\n\n```\npip install beautifulsoup4\n```\n\nIn most cases, assuming you've installed version 4.7.0, that should be all you need to do, but if you've installed via\nsome alternative method, and Soup Sieve is not automatically installed, you can install it directly:\n\n```\npip install soupsieve\n```\n\nIf you want to manually install it from source, first ensure that [`build`](https://pypi.org/project/build/) is\ninstalled:\n\n```\npip install build\n```\n\nThen navigate to the root of the project and build the wheel and install (replacing `` with the current version):\n\n```\npython -m build -w\npip install dist/soupsive--py3-none-any.whl\n```\n\n## Documentation\n\nDocumentation is found here: https://facelessuser.github.io/soupsieve/.\n\n## License\n\nMIT\n\n[bs4]: https://beautiful-soup-4.readthedocs.io/en/latest/#\n\n[github-ci-image]: https://github.com/facelessuser/soupsieve/workflows/build/badge.svg?branch=master&event=push\n[github-ci-link]: https://github.com/facelessuser/soupsieve/actions?query=workflow%3Abuild+branch%3Amaster\n[discord-image]: https://img.shields.io/discord/678289859768745989?logo=discord&logoColor=aaaaaa&color=mediumpurple&labelColor=333333\n[discord-link]:https://discord.gg/XBnPUZF\n[codecov-image]: https://img.shields.io/codecov/c/github/facelessuser/soupsieve/master.svg?logo=codecov&logoColor=aaaaaa&labelColor=333333\n[codecov-link]: https://codecov.io/github/facelessuser/soupsieve\n[pypi-image]: https://img.shields.io/pypi/v/soupsieve.svg?logo=pypi&logoColor=aaaaaa&labelColor=333333\n[pypi-down]: https://img.shields.io/pypi/dm/soupsieve.svg?logo=pypi&logoColor=aaaaaa&labelColor=333333\n[pypi-link]: https://pypi.python.org/pypi/soupsieve\n[python-image]: https://img.shields.io/pypi/pyversions/soupsieve?logo=python&logoColor=aaaaaa&labelColor=333333\n[license-image-mit]: https://img.shields.io/badge/license-MIT-blue.svg?labelColor=333333\n[donate-image]: https://img.shields.io/badge/Donate-PayPal-3fabd1?logo=paypal\n[donate-link]: https://www.paypal.me/facelessuser\n", + "description_content_type": "text/markdown", + "keywords": [ + "CSS", + "HTML", + "XML", + "filter", + "query", + "selector", + "soup" + ], + "author_email": "Isaac Muse ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + "Topic :: Software Development :: Libraries :: Python Modules", + "Typing :: Typed" + ], + "requires_python": ">=3.8", + "project_url": [ + "Homepage, https://github.com/facelessuser/soupsieve" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/d5/e1/3e9013159b4cbb71df9bd7611cbf90dc2c621c8aeeb677fc41dad72f2261/webcolors-1.13-py3-none-any.whl", + "archive_info": { + "hash": "sha256=29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf", + "hashes": { + "sha256": "29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "webcolors", + "version": "1.13", + "summary": "A library for working with the color formats defined by HTML and CSS.", + "description": ".. -*-restructuredtext-*-\n\n.. image:: https://github.com/ubernostrum/webcolors/workflows/CI/badge.svg\n :alt: CI status image\n :target: https://github.com/ubernostrum/webcolors/actions?query=workflow%3ACI\n\n``webcolors`` is a module for working with HTML/CSS color definitions.\n\nSupport is included for normalizing and converting between the\nfollowing formats (RGB colorspace only; conversion to/from HSL can be\nhandled by the ``colorsys`` module in the Python standard library):\n\n* Specification-defined color names\n\n* Six-digit hexadecimal\n\n* Three-digit hexadecimal\n\n* Integer ``rgb()`` triplet\n\n* Percentage ``rgb()`` triplet\n\nFor example:\n\n.. code-block:: python\n\n >>> import webcolors\n >>> webcolors.hex_to_name(\"#daa520\")\n 'goldenrod'\n\nImplementations are also provided for the HTML5 color parsing and\nserialization algorithms. For example, parsing the infamous\n\"chucknorris\" string into an rgb() triplet:\n\n.. code-block:: python\n\n >>> import webcolors\n >>> webcolors.html5_parse_legacy_color(\"chucknorris\")\n HTML5SimpleColor(red=192, green=0, blue=0)\n\nFull documentation is `available online `_.\n", + "description_content_type": "text/x-rst", + "keywords": [ + "color", + "css", + "html", + "web" + ], + "author_email": "James Bennett ", + "license": "BSD-3-Clause", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Utilities" + ], + "requires_dist": [ + "furo ; extra == 'docs'", + "sphinx ; extra == 'docs'", + "sphinx-copybutton ; extra == 'docs'", + "sphinx-inline-tabs ; extra == 'docs'", + "sphinx-notfound-page ; extra == 'docs'", + "sphinxext-opengraph ; extra == 'docs'", + "pytest ; extra == 'tests'", + "pytest-cov ; extra == 'tests'" + ], + "requires_python": ">=3.7", + "project_url": [ + "documentation, https://webcolors.readthedocs.io", + "homepage, https://github.com/ubernostrum/webcolors" + ], + "provides_extra": [ + "docs", + "tests" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "hashes": { + "sha256": "a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.0", + "name": "webencodings", + "version": "0.5.1", + "platform": [ + "UNKNOWN" + ], + "summary": "Character encoding aliases for legacy web content", + "description": "python-webencodings\n===================\n\nThis is a Python implementation of the `WHATWG Encoding standard\n`_.\n\n* Latest documentation: http://packages.python.org/webencodings/\n* Source code and issue tracker:\n https://github.com/gsnedders/python-webencodings\n* PyPI releases: http://pypi.python.org/pypi/webencodings\n* License: BSD\n* Python 2.6+ and 3.3+\n\nIn order to be compatible with legacy web content\nwhen interpreting something like ``Content-Type: text/html; charset=latin1``,\ntools need to use a particular set of aliases for encoding labels\nas well as some overriding rules.\nFor example, ``US-ASCII`` and ``iso-8859-1`` on the web are actually\naliases for ``windows-1252``, and an UTF-8 or UTF-16 BOM takes precedence\nover any other encoding declaration.\nThe Encoding standard defines all such details so that implementations do\nnot have to reverse-engineer each other.\n\nThis module has encoding labels and BOM detection,\nbut the actual implementation for encoders and decoders is Python’s.\n\n\n", + "home_page": "https://github.com/SimonSapin/python-webencodings", + "author": "Geoffrey Sneddon", + "author_email": "me@gsnedders.com", + "license": "BSD", + "classifier": [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Internet :: WWW/HTTP" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", + "archive_info": { + "hash": "sha256=3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", + "hashes": { + "sha256": "3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "fqdn", + "version": "1.5.1", + "platform": [ + "UNKNOWN" + ], + "summary": "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers", + "description": "UNKNOWN\n\n\n", + "keywords": [ + "fqdn", + "domain", + "hostname", + "RFC3686", + "dns" + ], + "home_page": "https://github.com/ypcrts/fqdn", + "author": "ypcrts", + "author_email": "ypcrts@users.noreply.github.com", + "license": "MPL 2.0", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Internet :: Name Service (DNS)", + "Topic :: Internet", + "Topic :: System :: Systems Administration", + "Topic :: Utilities" + ], + "requires_dist": [ + "cached-property (>=1.3.0) ; python_version < \"3.8\"" + ], + "requires_python": ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", + "hashes": { + "sha256": "b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "isoduration", + "version": "20.11.0", + "platform": [ + "UNKNOWN" + ], + "summary": "Operations with ISO 8601 durations", + "description": "# isoduration: Operations with ISO 8601 durations.\n\n[![PyPI Package](https://img.shields.io/pypi/v/isoduration?style=flat-square)](https://pypi.org/project/isoduration/)\n\n## What is this.\n\nISO 8601 is most commonly known as a way to exchange datetimes in textual format. A\nlesser known aspect of the standard is the representation of durations. They have a\nshape similar to this:\n\n```\nP3Y6M4DT12H30M5S\n```\n\nThis string represents a duration of 3 years, 6 months, 4 days, 12 hours, 30 minutes,\nand 5 seconds.\n\nThe state of the art of ISO 8601 duration handling in Python is more or less limited to\nwhat's offered by [`isodate`](https://pypi.org/project/isodate/). What we are trying to\nachieve here is to address the shortcomings of `isodate` (as described in their own\n[_Limitations_](https://github.com/gweis/isodate/#limitations) section), and a few of\nour own annoyances with their interface, such as the lack of uniformity in their\nhandling of types, and the use of regular expressions for parsing.\n\n## How to use it.\n\nThis package revolves around the [`Duration`](src/isoduration/types.py) type.\n\nGiven a ISO duration string we can produce such a type by using the `parse_duration()`\nfunction:\n\n```py\n>>> from isoduration import parse_duration\n>>> duration = parse_duration(\"P3Y6M4DT12H30M5S\")\n>>> duration.date\nDateDuration(years=Decimal('3'), months=Decimal('6'), days=Decimal('4'), weeks=Decimal('0'))\n>>> duration.time\nTimeDuration(hours=Decimal('12'), minutes=Decimal('30'), seconds=Decimal('5'))\n```\n\nThe `date` and `time` portions of the parsed duration are just regular\n[dataclasses](https://docs.python.org/3/library/dataclasses.html), so their members can\nbe accessed in a non-surprising way.\n\nBesides just parsing them, a number of additional operations are available:\n\n- Durations can be compared and negated:\n ```py\n >>> parse_duration(\"P3Y4D\") == parse_duration(\"P3Y4DT0H\")\n True\n >>> -parse_duration(\"P3Y4D\")\n Duration(DateDuration(years=Decimal('-3'), months=Decimal('0'), days=Decimal('-4'), weeks=Decimal('0')), TimeDuration(hours=Decimal('0'), minutes=Decimal('0'), seconds=Decimal('0')))\n ```\n- Durations can be added to, or subtracted from, Python datetimes:\n ```py\n >>> from datetime import datetime\n >>> datetime(2020, 3, 15) + parse_duration(\"P2Y\")\n datetime.datetime(2022, 3, 15, 0, 0)\n >>> datetime(2020, 3, 15) - parse_duration(\"P33Y1M4D\")\n datetime.datetime(1987, 2, 11, 0, 0)\n ```\n- Durations are hashable, so they can be used as dictionary keys or as part of sets.\n- Durations can be formatted back to a ISO 8601-compliant duration string:\n ```py\n >>> from isoduration import parse_duration, format_duration\n >>> format_duration(parse_duration(\"P11YT2H\"))\n 'P11YT2H'\n >>> str(parse_duration(\"P11YT2H\"))\n 'P11YT2H'\n ```\n\n## How to improve it.\n\nThese steps, in this order, should land you in a development environment:\n\n```sh\ngit clone git@github.com:bolsote/isoduration.git\ncd isoduration/\npython -m venv ve\n. ve/bin/activate\npip install -U pip\npip install -e .\npip install -r requirements/dev.txt\n```\n\nAdapt to your own likings and/or needs.\n\nTesting is driven by [tox](https://tox.readthedocs.io). The output of `tox -l` and a\ncareful read of [tox.ini](tox.ini) should get you there.\n\n## FAQs.\n\n### How come `P1Y != P365D`?\nSome years have 366 days. If it's not always the same, then it's not the same.\n\n### Why do you create your own types, instead of somewhat shoehorning a `timedelta`?\n`timedelta` cannot represent certain durations, such as those involving years or months.\nSince it cannot represent all possible durations without dangerous arithmetic, then it\nmust not be the right type.\n\n### Why don't you use regular expressions to parse duration strings?\n[Regular expressions should only be used to parse regular languages.](https://stackoverflow.com/a/1732454)\n\n### Why is parsing the inverse of formatting, but the converse is not true?\nBecause this wonderful representation is not unique.\n\n### Why do you support ``?\nProbably because the standard made me to.\n\n### Why do you not support ``?\nProbably because the standard doesn't allow me to.\n\n### Why is it not possible to subtract a datetime from a duration?\nI'm confused.\n\n### Why should I use this over some other thing?\nYou shouldn't do what people on the Internet tell you to do.\n\n### Why are ISO standards so strange?\nYes.\n\n## References.\n\n- [XML Schema Part 2: Datatypes, Appendix D](https://www.w3.org/TR/xmlschema-2/#isoformats):\n This excitingly named document contains more details about ISO 8601 than any human\n should be allowed to understand.\n- [`isodate`](https://pypi.org/project/isodate/): The original implementation of ISO\n durations in Python. Worth a look. But ours is cooler.\n\n\n", + "description_content_type": "text/markdown", + "keywords": [ + "datetime", + "date", + "time", + "duration", + "duration-parsing", + "duration-string", + "iso8601", + "iso8601-duration" + ], + "home_page": "https://github.com/bolsote/isoduration", + "author": "Víctor Muñoz", + "author_email": "victorm@marshland.es", + "license": "UNKNOWN", + "classifier": [ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", + "License :: OSI Approved :: ISC License (ISCL)", + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries :: Python Modules" + ], + "requires_dist": [ + "arrow (>=0.15.0)" + ], + "requires_python": ">=3.7", + "project_url": [ + "Repository, https://github.com/bolsote/isoduration", + "Bug Reports, https://github.com/bolsote/isoduration/issues", + "Changelog, https://github.com/bolsote/isoduration/blob/master/CHANGELOG" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/2b/27/77f9d5684e6bce929f5cfe18d6cfbe5133013c06cb2fbf5933670e60761d/pure_eval-0.2.2-py3-none-any.whl", + "archive_info": { + "hash": "sha256=01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", + "hashes": { + "sha256": "01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "pure-eval", + "version": "0.2.2", + "platform": [ + "UNKNOWN" + ], + "summary": "Safely evaluate AST nodes without side effects", + "description": "# `pure_eval`\n\n[![Build Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master) [![Supports Python versions 3.5+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval)\n\nThis is a Python package that lets you safely evaluate certain AST nodes without triggering arbitrary code that may have unwanted side effects.\n\nIt can be installed from PyPI:\n\n pip install pure_eval\n\nTo demonstrate usage, suppose we have an object defined as follows:\n\n```python\nclass Rectangle:\n def __init__(self, width, height):\n self.width = width\n self.height = height\n\n @property\n def area(self):\n print(\"Calculating area...\")\n return self.width * self.height\n\n\nrect = Rectangle(3, 5)\n```\n\nGiven the `rect` object, we want to evaluate whatever expressions we can in this source code:\n\n```python\nsource = \"(rect.width, rect.height, rect.area)\"\n```\n\nThis library works with the AST, so let's parse the source code and peek inside:\n\n```python\nimport ast\n\ntree = ast.parse(source)\nthe_tuple = tree.body[0].value\nfor node in the_tuple.elts:\n print(ast.dump(node))\n```\n\nOutput:\n\n```python\nAttribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load())\nAttribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load())\nAttribute(value=Name(id='rect', ctx=Load()), attr='area', ctx=Load())\n```\n\nNow to actually use the library. First construct an Evaluator:\n\n```python\nfrom pure_eval import Evaluator\n\nevaluator = Evaluator({\"rect\": rect})\n```\n\nThe argument to `Evaluator` should be a mapping from variable names to their values. Or if you have access to the stack frame where `rect` is defined, you can instead use:\n\n```python\nevaluator = Evaluator.from_frame(frame)\n```\n\nNow to evaluate some nodes, using `evaluator[node]`:\n\n```python\nprint(\"rect.width:\", evaluator[the_tuple.elts[0]])\nprint(\"rect:\", evaluator[the_tuple.elts[0].value])\n```\n\nOutput:\n\n```\nrect.width: 3\nrect: <__main__.Rectangle object at 0x105b0dd30>\n```\n\nOK, but you could have done the same thing with `eval`. The useful part is that it will refuse to evaluate the property `rect.area` because that would trigger unknown code. If we try, it'll raise a `CannotEval` exception.\n\n```python\nfrom pure_eval import CannotEval\n\ntry:\n print(\"rect.area:\", evaluator[the_tuple.elts[2]]) # fails\nexcept CannotEval as e:\n print(e) # prints CannotEval\n```\n\nTo find all the expressions that can be evaluated in a tree:\n\n```python\nfor node, value in evaluator.find_expressions(tree):\n print(ast.dump(node), value)\n```\n\nOutput:\n\n```python\nAttribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load()) 3\nAttribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load()) 5\nName(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>\nName(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>\nName(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>\n```\n\nNote that this includes `rect` three times, once for each appearance in the source code. Since all these nodes are equivalent, we can group them together:\n\n```python\nfrom pure_eval import group_expressions\n\nfor nodes, values in group_expressions(evaluator.find_expressions(tree)):\n print(len(nodes), \"nodes with value:\", values)\n```\n\nOutput:\n\n```\n1 nodes with value: 3\n1 nodes with value: 5\n3 nodes with value: <__main__.Rectangle object at 0x10d374d30>\n```\n\nIf we want to list all the expressions in a tree, we may want to filter out certain expressions whose values are obvious. For example, suppose we have a function `foo`:\n\n```python\ndef foo():\n pass\n```\n\nIf we refer to `foo` by its name as usual, then that's not interesting:\n\n```python\nfrom pure_eval import is_expression_interesting\n\nnode = ast.parse('foo').body[0].value\nprint(ast.dump(node))\nprint(is_expression_interesting(node, foo))\n```\n\nOutput:\n\n```python\nName(id='foo', ctx=Load())\nFalse\n```\n\nBut if we refer to it by a different name, then it's interesting:\n\n```python\nnode = ast.parse('bar').body[0].value\nprint(ast.dump(node))\nprint(is_expression_interesting(node, foo))\n```\n\nOutput:\n\n```python\nName(id='bar', ctx=Load())\nTrue\n```\n\nIn general `is_expression_interesting` returns False for the following values:\n- Literals (e.g. `123`, `'abc'`, `[1, 2, 3]`, `{'a': (), 'b': ([1, 2], [3])}`)\n- Variables or attributes whose name is equal to the value's `__name__`, such as `foo` above or `self.foo` if it was a method.\n- Builtins (e.g. `len`) referred to by their usual name.\n\nTo make things easier, you can combine finding expressions, grouping them, and filtering out the obvious ones with:\n\n```python\nevaluator.interesting_expressions_grouped(root)\n```\n\nTo get the source code of an AST node, I recommend [asttokens](https://github.com/gristlabs/asttokens).\n\nHere's a complete example that brings it all together:\n\n```python\nfrom asttokens import ASTTokens\nfrom pure_eval import Evaluator\n\nsource = \"\"\"\nx = 1\nd = {x: 2}\ny = d[x]\n\"\"\"\n\nnames = {}\nexec(source, names)\natok = ASTTokens(source, parse=True)\nfor nodes, value in Evaluator(names).interesting_expressions_grouped(atok.tree):\n print(atok.get_text(nodes[0]), \"=\", value)\n```\n\nOutput:\n\n```python\nx = 1\nd = {1: 2}\ny = 2\nd[x] = 2\n```\n\n\n", + "description_content_type": "text/markdown", + "home_page": "http://github.com/alexmojaki/pure_eval", + "author": "Alex Hall", + "author_email": "alex.mojaki@gmail.com", + "license": "MIT", + "classifier": [ + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent" + ], + "requires_dist": [ + "pytest ; extra == 'tests'" + ], + "provides_extra": [ + "tests" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", + "hashes": { + "sha256": "a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "uri-template", + "version": "1.3.0", + "summary": "RFC 6570 URI Template Processor", + "description": "# uri-template\n\nAn implementation of RFC 6570 URI Templates.\n\nThis packages implements URI Template expansion in strict adherence to RFC 6570,\nbut adds a few extensions.\n\n## RFC 6570 Extensions\n\n### Non-string Values\n\nRFC 6570 is silent regarding variable values that are not strings, lists, associative arrays, or null.\n\nThis package handles value types as follows:\n\n * Values that are instances of `str` are treated as strings.\n * Values implementing `collections.abc.Sequence` are treated as lists.\n * Values implementing `collections.abc.Mapping` are treated as associative arrays.\n * `None` values are treated as null.\n * Boolean values are converted to the lower case strings 'true' and 'false'.\n * All other values will be converted to strings using the Python `str()` function.\n\n### Nested Structures\n\nThis package handles variable values with nested structure,\nfor example, lists containing other lists or associative arrays,\nor associative arrays containing lists or other associative arrays.\n\nNested values for variables that do not use the array modifier ('[]') are treated as follows:\n\n * Lists containing lists are flattened into a single list.\n * Lists containing associative arrays are treated as a single combined associative array.\n * Associative arrays represent nested data using dot notation (\".\") for the variable names.\n\nNested values for variables that use the array modifier extend the variable name with \nthe value's index or key written as an array subscript, e.g. \"foo[0]\" or \"foo[bar]\".\n\n### Default Values\n\nThis package allows default string values for variables per early drafts of RFC 6570.\ne.g. \"{foo=bar}\" will expand to \"bar\" if a value for `foo` is not given.\n\nList and associtative array default values are not supported at this time.\n\n### Specifying Value Keys\n\nSometimes a URI Template is used to provide glue between an API and a given set of data.\nIn this case, the names of values needed in the final URL may not match the data provided \nfor the expansion.\n\nThis package allows specifying the key used to pass data into the template. \ne.g. \"{?foo/bar}\" will expand to \"?foo=\"\n\n### Partial expansion\n\nThis package allows partial expansion of URI Templates.\n\nIn a partial expansion, missing values preseve their expansion in the resultant output.\ne.g. a partial expansion of \"{one}/{two}\" with a value for `one` of \"foo\" and `two` missing will result in:\n\"foo/{two}\".\n\nIn order to allow partial expansions to preserve value joiners with expanded output,\nexpansions accept an optional \"trailing joiner\" of \",\", \".\", \"/\", \";\", or \"&\",\nif this joiner is present after all variables, \nit will be appended to the output of the expansion and will suppress the output prefix.\ne.g.: \"{#one,two}\" with a missing value for `one` and a value of \"bar\" for `two`, \nwill partially expand to: \"#{#one,}bar\", which when provided with a value of \"foo\" for `one` \nwill expand to \"#foo,bar\"\n\nSome partial expansions that have some output, but have missing values, \nwill convert the remaining variables to a different type of expansion so that \nfurther expansions will produce the same output as if all values were originally present.\n\n * Partial Simple String Expansions will convert to Comma Expansions.\n * Partial Reserved Expansions Partial Fragment Expansions will convert to Reserved Comma Expansions.\n * Partial Form-Style Query Expansions will convert to Form-Style Query Continuations.\n\nIn order to preserve the resultant value of templates that are paritally expanded, \nthe following additional Expression Expansions are supported:\n\n#### Comma Expansion: {,var}\n\nSimilar to Label Expansion with Dot-Prefix, \nComma Expansion prefixes the expansion output with a single comma \",\".\n\n#### Reserved Comma Expansion: {,+var}\n\nSimilar to Comma Expansion, \nReserved Comma Expansion prefixes the expansion output with a single comma \",\",\nbut otherwise performs a Reserved Expansion ({+var}).\n\n## API \n\nThe package provides three functions:\n\n#### uri_template.expand(template: str, **kwargs) -> (str | None): ...\n\nExpand the given template, skipping missing values per RFC 6570.\n\nReturns `None` if the template is invalid or expansion fails.\n\n\n#### uri_template.partial(template: str, **kwargs) -> (str | None): ...\n\nPartially expand the given template, \nreplacing missing variables with further expansions.\n\nReturns `None` if the template is invalid or expansion fails.\n\n\n#### uri_template.validate(template: str) -> bool: ...\n\nReturn `True` if the template is valid.\n\n---\n\nAnd the following classes:\n\n### uri_template.URITemplate\n\n#### URITemplate(template: str)\n\nConstruct a URITemplate for a given template string.\n\nRaises `ExpansionInvalid`, `ExpansionReserved`, or `VariableInvalid` if the template is invalid or unsupported.\n\n#### URITemplate.variables: Iterable[Variable]\n\nAll variables present in the template.\nDuplicates are returned once, order is preserved.\n\n#### URITemplate.variable_names: Iterable[str]\n\nThe names of all variables present in the template.\nDuplicates are returned once, order is preserved.\n\n#### URITemplate.expanded: bool\n\nDetermine if template is fully expanded.\n\n#### URITemplate.expand(**kwargs) -> str\n\nReturns the result of the expansion, skips missing variables.\n\nRaises `ExpansionFailed` if the expansion fails due to a composite value being passed to a variable with a prefix modifier.\n\n#### URITemplate.partial(**kwargs) -> URITemplate\n\nExpand the template, replacing missing variables with further expansions.\n\nRaises `ExpansionFailed` if the expansion fails due to a composite value being passed to a variable with a prefix modifier.\n\n#### URITemplate.__str__() -> str\n\nConvert the URITemplate object back into its original string form.\n\n---\n\n### uri_template.Variable\n\n#### Variable(var_spec: str)\n\nConstruct a Variable.\n\n#### Variable.name: str\n\nThe name of the variable\n\n#### Variable.max_length: int\n\nThe speicified max length, or `0`.\n\n#### Variable.explode: bool\n\nExplode modifier is present.\n\n#### Variable.array: bool\n\nArray modifier is present.\n\n#### Variable.default: (str | None)\n\nSpecified default value, or `None`.\n\n#### Variable.__str__() -> str\n\nConvert the variable back to its original string form.\n\n---\n\nAnd the following exceptions:\n\n#### uri_template.ExpansionInvalid\n\nExpansion specification is invalid. \n\nRaised by URITemplate constructor.\n\n#### uri_template.ExpansionReserved\n\nExpansion contains a reserved operator.\n\nRaised by URITemplate constructor.\n\n#### uri_template.VariableInvalid\n\nVariable specification is invalid.\n\nRaised by URITemplate constructor.\n\n#### uri_template.ExpansionFailed\n\nExpansion failed, currently only possible when a composite value is passed to a variable with a prefix modifier.\n\nRaised by URITemplate.expand() or URITemplate.partial() methods.\n\n\n## Installation\n\nInstall with pip:\n\n pip install uri-template\n", + "description_content_type": "text/markdown", + "keywords": [ + "config" + ], + "author_email": "Peter Linss ", + "license": "MIT License", + "classifier": [ + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Software Development :: Libraries :: Python Modules" + ], + "requires_dist": [ + "types-PyYAML ; extra == 'dev'", + "mypy ; extra == 'dev'", + "flake8 ; extra == 'dev'", + "flake8-annotations ; extra == 'dev'", + "flake8-bandit ; extra == 'dev'", + "flake8-bugbear ; extra == 'dev'", + "flake8-commas ; extra == 'dev'", + "flake8-comprehensions ; extra == 'dev'", + "flake8-continuation ; extra == 'dev'", + "flake8-datetimez ; extra == 'dev'", + "flake8-docstrings ; extra == 'dev'", + "flake8-import-order ; extra == 'dev'", + "flake8-literal ; extra == 'dev'", + "flake8-modern-annotations ; extra == 'dev'", + "flake8-noqa ; extra == 'dev'", + "flake8-pyproject ; extra == 'dev'", + "flake8-requirements ; extra == 'dev'", + "flake8-typechecking-import ; extra == 'dev'", + "flake8-use-fstring ; extra == 'dev'", + "pep8-naming ; extra == 'dev'" + ], + "requires_python": ">=3.7", + "project_url": [ + "homepage, https://gitlab.linss.com/open-source/python/uri-template" + ], + "provides_extra": [ + "dev" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", + "hashes": { + "sha256": "3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "wcwidth", + "version": "0.2.13", + "summary": "Measures the displayed width of unicode strings in a terminal", + "description": "|pypi_downloads| |codecov| |license|\n\n============\nIntroduction\n============\n\nThis library is mainly for CLI programs that carefully produce output for\nTerminals, or make pretend to be an emulator.\n\n**Problem Statement**: The printable length of *most* strings are equal to the\nnumber of cells they occupy on the screen ``1 character : 1 cell``. However,\nthere are categories of characters that *occupy 2 cells* (full-wide), and\nothers that *occupy 0* cells (zero-width).\n\n**Solution**: POSIX.1-2001 and POSIX.1-2008 conforming systems provide\n`wcwidth(3)`_ and `wcswidth(3)`_ C functions of which this python module's\nfunctions precisely copy. *These functions return the number of cells a\nunicode string is expected to occupy.*\n\nInstallation\n------------\n\nThe stable version of this package is maintained on pypi, install using pip::\n\n pip install wcwidth\n\nExample\n-------\n\n**Problem**: given the following phrase (Japanese),\n\n >>> text = u'コンニチハ'\n\nPython **incorrectly** uses the *string length* of 5 codepoints rather than the\n*printable length* of 10 cells, so that when using the `rjust` function, the\noutput length is wrong::\n\n >>> print(len('コンニチハ'))\n 5\n\n >>> print('コンニチハ'.rjust(20, '_'))\n _______________コンニチハ\n\nBy defining our own \"rjust\" function that uses wcwidth, we can correct this::\n\n >>> def wc_rjust(text, length, padding=' '):\n ... from wcwidth import wcswidth\n ... return padding * max(0, (length - wcswidth(text))) + text\n ...\n\nOur **Solution** uses wcswidth to determine the string length correctly::\n\n >>> from wcwidth import wcswidth\n >>> print(wcswidth('コンニチハ'))\n 10\n\n >>> print(wc_rjust('コンニチハ', 20, '_'))\n __________コンニチハ\n\n\nChoosing a Version\n------------------\n\nExport an environment variable, ``UNICODE_VERSION``. This should be done by\n*terminal emulators* or those developers experimenting with authoring one of\ntheir own, from shell::\n\n $ export UNICODE_VERSION=13.0\n\nIf unspecified, the latest version is used. If your Terminal Emulator does not\nexport this variable, you can use the `jquast/ucs-detect`_ utility to\nautomatically detect and export it to your shell.\n\nwcwidth, wcswidth\n-----------------\nUse function ``wcwidth()`` to determine the length of a *single unicode\ncharacter*, and ``wcswidth()`` to determine the length of many, a *string\nof unicode characters*.\n\nBriefly, return values of function ``wcwidth()`` are:\n\n``-1``\n Indeterminate (not printable).\n\n``0``\n Does not advance the cursor, such as NULL or Combining.\n\n``2``\n Characters of category East Asian Wide (W) or East Asian\n Full-width (F) which are displayed using two terminal cells.\n\n``1``\n All others.\n\nFunction ``wcswidth()`` simply returns the sum of all values for each character\nalong a string, or ``-1`` when it occurs anywhere along a string.\n\nFull API Documentation at https://wcwidth.readthedocs.org\n\n==========\nDeveloping\n==========\n\nInstall wcwidth in editable mode::\n\n pip install -e .\n\nExecute unit tests using tox_::\n\n tox -e py27,py35,py36,py37,py38,py39,py310,py311,py312\n\nUpdating Unicode Version\n------------------------\n\nRegenerate python code tables from latest Unicode Specification data files::\n\n tox -e update\n\nThe script is located at ``bin/update-tables.py``, requires Python 3.9 or\nlater. It is recommended but not necessary to run this script with the newest\nPython, because the newest Python has the latest ``unicodedata`` for generating\ncomments.\n\nBuilding Documentation\n----------------------\n\nThis project is using `sphinx`_ 4.5 to build documentation::\n\n tox -e sphinx\n\nThe output will be in ``docs/_build/html/``.\n\nUpdating Requirements\n---------------------\n\nThis project is using `pip-tools`_ to manage requirements.\n\nTo upgrade requirements for updating unicode version, run::\n\n tox -e update_requirements_update\n\nTo upgrade requirements for testing, run::\n\n tox -e update_requirements37,update_requirements39\n\nTo upgrade requirements for building documentation, run::\n\n tox -e update_requirements_docs\n\nUtilities\n---------\n\nSupplementary tools for browsing and testing terminals for wide unicode\ncharacters are found in the `bin/`_ of this project's source code. Just ensure\nto first ``pip install -r requirements-develop.txt`` from this projects main\nfolder. For example, an interactive browser for testing::\n\n python ./bin/wcwidth-browser.py\n\n====\nUses\n====\n\nThis library is used in:\n\n- `jquast/blessed`_: a thin, practical wrapper around terminal capabilities in\n Python.\n\n- `prompt-toolkit/python-prompt-toolkit`_: a Library for building powerful\n interactive command lines in Python.\n\n- `dbcli/pgcli`_: Postgres CLI with autocompletion and syntax highlighting.\n\n- `thomasballinger/curtsies`_: a Curses-like terminal wrapper with a display\n based on compositing 2d arrays of text.\n\n- `selectel/pyte`_: Simple VTXXX-compatible linux terminal emulator.\n\n- `astanin/python-tabulate`_: Pretty-print tabular data in Python, a library\n and a command-line utility.\n\n- `rspeer/python-ftfy`_: Fixes mojibake and other glitches in Unicode\n text.\n\n- `nbedos/termtosvg`_: Terminal recorder that renders sessions as SVG\n animations.\n\n- `peterbrittain/asciimatics`_: Package to help people create full-screen text\n UIs.\n\n- `python-cmd2/cmd2`_: A tool for building interactive command line apps\n\n- `stratis-storage/stratis-cli`_: CLI for the Stratis project\n\n- `ihabunek/toot`_: A Mastodon CLI/TUI client\n\n- `saulpw/visidata`_: Terminal spreadsheet multitool for discovering and\n arranging data\n\n===============\nOther Languages\n===============\n\n- `timoxley/wcwidth`_: JavaScript\n- `janlelis/unicode-display_width`_: Ruby\n- `alecrabbit/php-wcwidth`_: PHP\n- `Text::CharWidth`_: Perl\n- `bluebear94/Terminal-WCWidth`_: Perl 6\n- `mattn/go-runewidth`_: Go\n- `grepsuzette/wcwidth`_: Haxe\n- `aperezdc/lua-wcwidth`_: Lua\n- `joachimschmidt557/zig-wcwidth`_: Zig\n- `fumiyas/wcwidth-cjk`_: `LD_PRELOAD` override\n- `joshuarubin/wcwidth9`_: Unicode version 9 in C\n\n=======\nHistory\n=======\n\n0.2.13 *2024-01-06*\n * **Bugfix** zero-width support for Hangul Jamo (Korean)\n\n0.2.12 *2023-11-21*\n * re-release to remove .pyi file misplaced in wheel files `Issue #101`_.\n\n0.2.11 *2023-11-20*\n * Include tests files in the source distribution (`PR #98`_, `PR #100`_).\n\n0.2.10 *2023-11-13*\n * **Bugfix** accounting of some kinds of emoji sequences using U+FE0F\n Variation Selector 16 (`PR #97`_).\n * **Updated** `Specification `_.\n\n0.2.9 *2023-10-30*\n * **Bugfix** zero-width characters used in Emoji ZWJ sequences, Balinese,\n Jamo, Devanagari, Tamil, Kannada and others (`PR #91`_).\n * **Updated** to include `Specification `_ of\n character measurements.\n\n0.2.8 *2023-09-30*\n * Include requirements files in the source distribution (`PR #82`_).\n\n0.2.7 *2023-09-28*\n * **Updated** tables to include Unicode Specification 15.1.0.\n * Include ``bin``, ``docs``, and ``tox.ini`` in the source distribution\n\n0.2.6 *2023-01-14*\n * **Updated** tables to include Unicode Specification 14.0.0 and 15.0.0.\n * **Changed** developer tools to use pip-compile, and to use jinja2 templates\n for code generation in `bin/update-tables.py` to prepare for possible\n compiler optimization release.\n\n0.2.1 .. 0.2.5 *2020-06-23*\n * **Repository** changes to update tests and packaging issues, and\n begin tagging repository with matching release versions.\n\n0.2.0 *2020-06-01*\n * **Enhancement**: Unicode version may be selected by exporting the\n Environment variable ``UNICODE_VERSION``, such as ``13.0``, or ``6.3.0``.\n See the `jquast/ucs-detect`_ CLI utility for automatic detection.\n * **Enhancement**:\n API Documentation is published to readthedocs.org.\n * **Updated** tables for *all* Unicode Specifications with files\n published in a programmatically consumable format, versions 4.1.0\n through 13.0\n\n0.1.9 *2020-03-22*\n * **Performance** optimization by `Avram Lubkin`_, `PR #35`_.\n * **Updated** tables to Unicode Specification 13.0.0.\n\n0.1.8 *2020-01-01*\n * **Updated** tables to Unicode Specification 12.0.0. (`PR #30`_).\n\n0.1.7 *2016-07-01*\n * **Updated** tables to Unicode Specification 9.0.0. (`PR #18`_).\n\n0.1.6 *2016-01-08 Production/Stable*\n * ``LICENSE`` file now included with distribution.\n\n0.1.5 *2015-09-13 Alpha*\n * **Bugfix**:\n Resolution of \"combining_ character width\" issue, most especially\n those that previously returned -1 now often (correctly) return 0.\n resolved by `Philip Craig`_ via `PR #11`_.\n * **Deprecated**:\n The module path ``wcwidth.table_comb`` is no longer available,\n it has been superseded by module path ``wcwidth.table_zero``.\n\n0.1.4 *2014-11-20 Pre-Alpha*\n * **Feature**: ``wcswidth()`` now determines printable length\n for (most) combining_ characters. The developer's tool\n `bin/wcwidth-browser.py`_ is improved to display combining_\n characters when provided the ``--combining`` option\n (`Thomas Ballinger`_ and `Leta Montopoli`_ `PR #5`_).\n * **Feature**: added static analysis (prospector_) to testing\n framework.\n\n0.1.3 *2014-10-29 Pre-Alpha*\n * **Bugfix**: 2nd parameter of wcswidth was not honored.\n (`Thomas Ballinger`_, `PR #4`_).\n\n0.1.2 *2014-10-28 Pre-Alpha*\n * **Updated** tables to Unicode Specification 7.0.0.\n (`Thomas Ballinger`_, `PR #3`_).\n\n0.1.1 *2014-05-14 Pre-Alpha*\n * Initial release to pypi, Based on Unicode Specification 6.3.0\n\nThis code was originally derived directly from C code of the same name,\nwhose latest version is available at\nhttps://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c::\n\n * Markus Kuhn -- 2007-05-26 (Unicode 5.0)\n *\n * Permission to use, copy, modify, and distribute this software\n * for any purpose and without fee is hereby granted. The author\n * disclaims all warranties with regard to this software.\n\n.. _`Specification_from_pypi`: https://wcwidth.readthedocs.io/en/latest/specs.html\n.. _`tox`: https://tox.wiki/en/latest/\n.. _`prospector`: https://github.com/landscapeio/prospector\n.. _`combining`: https://en.wikipedia.org/wiki/Combining_character\n.. _`bin/`: https://github.com/jquast/wcwidth/tree/master/bin\n.. _`bin/wcwidth-browser.py`: https://github.com/jquast/wcwidth/blob/master/bin/wcwidth-browser.py\n.. _`Thomas Ballinger`: https://github.com/thomasballinger\n.. _`Leta Montopoli`: https://github.com/lmontopo\n.. _`Philip Craig`: https://github.com/philipc\n.. _`PR #3`: https://github.com/jquast/wcwidth/pull/3\n.. _`PR #4`: https://github.com/jquast/wcwidth/pull/4\n.. _`PR #5`: https://github.com/jquast/wcwidth/pull/5\n.. _`PR #11`: https://github.com/jquast/wcwidth/pull/11\n.. _`PR #18`: https://github.com/jquast/wcwidth/pull/18\n.. _`PR #30`: https://github.com/jquast/wcwidth/pull/30\n.. _`PR #35`: https://github.com/jquast/wcwidth/pull/35\n.. _`PR #82`: https://github.com/jquast/wcwidth/pull/82\n.. _`PR #91`: https://github.com/jquast/wcwidth/pull/91\n.. _`PR #97`: https://github.com/jquast/wcwidth/pull/97\n.. _`PR #98`: https://github.com/jquast/wcwidth/pull/98\n.. _`PR #100`: https://github.com/jquast/wcwidth/pull/100\n.. _`Issue #101`: https://github.com/jquast/wcwidth/issues/101\n.. _`jquast/blessed`: https://github.com/jquast/blessed\n.. _`selectel/pyte`: https://github.com/selectel/pyte\n.. _`thomasballinger/curtsies`: https://github.com/thomasballinger/curtsies\n.. _`dbcli/pgcli`: https://github.com/dbcli/pgcli\n.. _`prompt-toolkit/python-prompt-toolkit`: https://github.com/prompt-toolkit/python-prompt-toolkit\n.. _`timoxley/wcwidth`: https://github.com/timoxley/wcwidth\n.. _`wcwidth(3)`: https://man7.org/linux/man-pages/man3/wcwidth.3.html\n.. _`wcswidth(3)`: https://man7.org/linux/man-pages/man3/wcswidth.3.html\n.. _`astanin/python-tabulate`: https://github.com/astanin/python-tabulate\n.. _`janlelis/unicode-display_width`: https://github.com/janlelis/unicode-display_width\n.. _`rspeer/python-ftfy`: https://github.com/rspeer/python-ftfy\n.. _`alecrabbit/php-wcwidth`: https://github.com/alecrabbit/php-wcwidth\n.. _`Text::CharWidth`: https://metacpan.org/pod/Text::CharWidth\n.. _`bluebear94/Terminal-WCWidth`: https://github.com/bluebear94/Terminal-WCWidth\n.. _`mattn/go-runewidth`: https://github.com/mattn/go-runewidth\n.. _`grepsuzette/wcwidth`: https://github.com/grepsuzette/wcwidth\n.. _`jquast/ucs-detect`: https://github.com/jquast/ucs-detect\n.. _`Avram Lubkin`: https://github.com/avylove\n.. _`nbedos/termtosvg`: https://github.com/nbedos/termtosvg\n.. _`peterbrittain/asciimatics`: https://github.com/peterbrittain/asciimatics\n.. _`aperezdc/lua-wcwidth`: https://github.com/aperezdc/lua-wcwidth\n.. _`joachimschmidt557/zig-wcwidth`: https://github.com/joachimschmidt557/zig-wcwidth\n.. _`fumiyas/wcwidth-cjk`: https://github.com/fumiyas/wcwidth-cjk\n.. _`joshuarubin/wcwidth9`: https://github.com/joshuarubin/wcwidth9\n.. _`python-cmd2/cmd2`: https://github.com/python-cmd2/cmd2\n.. _`stratis-storage/stratis-cli`: https://github.com/stratis-storage/stratis-cli\n.. _`ihabunek/toot`: https://github.com/ihabunek/toot\n.. _`saulpw/visidata`: https://github.com/saulpw/visidata\n.. _`pip-tools`: https://pip-tools.readthedocs.io/\n.. _`sphinx`: https://www.sphinx-doc.org/\n.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/wcwidth.svg?logo=pypi\n :alt: Downloads\n :target: https://pypi.org/project/wcwidth/\n.. |codecov| image:: https://codecov.io/gh/jquast/wcwidth/branch/master/graph/badge.svg\n :alt: codecov.io Code Coverage\n :target: https://app.codecov.io/gh/jquast/wcwidth/\n.. |license| image:: https://img.shields.io/pypi/l/wcwidth.svg\n :target: https://pypi.org/project/wcwidth/\n :alt: MIT License\n", + "keywords": [ + "cjk", + "combining", + "console", + "eastasian", + "emoji", + "emulator", + "terminal", + "unicode", + "wcswidth", + "wcwidth", + "xterm" + ], + "home_page": "https://github.com/jquast/wcwidth", + "author": "Jeff Quast", + "author_email": "contact@jeffquast.com", + "license": "MIT", + "classifier": [ + "Intended Audience :: Developers", + "Natural Language :: English", + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "License :: OSI Approved :: MIT License", + "Operating System :: POSIX", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Localization", + "Topic :: Software Development :: Internationalization", + "Topic :: Terminals" + ], + "requires_dist": [ + "backports.functools-lru-cache >=1.2.1 ; python_version < \"3.2\"" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", + "archive_info": { + "hash": "sha256=c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", + "hashes": { + "sha256": "c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "arrow", + "version": "1.3.0", + "summary": "Better dates & times for Python", + "description": "Arrow: Better dates & times for Python\n======================================\n\n.. start-inclusion-marker-do-not-remove\n\n.. image:: https://github.com/arrow-py/arrow/workflows/tests/badge.svg?branch=master\n :alt: Build Status\n :target: https://github.com/arrow-py/arrow/actions?query=workflow%3Atests+branch%3Amaster\n\n.. image:: https://codecov.io/gh/arrow-py/arrow/branch/master/graph/badge.svg\n :alt: Coverage\n :target: https://codecov.io/gh/arrow-py/arrow\n\n.. image:: https://img.shields.io/pypi/v/arrow.svg\n :alt: PyPI Version\n :target: https://pypi.python.org/pypi/arrow\n\n.. image:: https://img.shields.io/pypi/pyversions/arrow.svg\n :alt: Supported Python Versions\n :target: https://pypi.python.org/pypi/arrow\n\n.. image:: https://img.shields.io/pypi/l/arrow.svg\n :alt: License\n :target: https://pypi.python.org/pypi/arrow\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :alt: Code Style: Black\n :target: https://github.com/psf/black\n\n\n**Arrow** is a Python library that offers a sensible and human-friendly approach to creating, manipulating, formatting and converting dates, times and timestamps. It implements and updates the datetime type, plugging gaps in functionality and providing an intelligent module API that supports many common creation scenarios. Simply put, it helps you work with dates and times with fewer imports and a lot less code.\n\nArrow is named after the `arrow of time `_ and is heavily inspired by `moment.js `_ and `requests `_.\n\nWhy use Arrow over built-in modules?\n------------------------------------\n\nPython's standard library and some other low-level modules have near-complete date, time and timezone functionality, but don't work very well from a usability perspective:\n\n- Too many modules: datetime, time, calendar, dateutil, pytz and more\n- Too many types: date, time, datetime, tzinfo, timedelta, relativedelta, etc.\n- Timezones and timestamp conversions are verbose and unpleasant\n- Timezone naivety is the norm\n- Gaps in functionality: ISO 8601 parsing, timespans, humanization\n\nFeatures\n--------\n\n- Fully-implemented, drop-in replacement for datetime\n- Support for Python 3.6+\n- Timezone-aware and UTC by default\n- Super-simple creation options for many common input scenarios\n- ``shift`` method with support for relative offsets, including weeks\n- Format and parse strings automatically\n- Wide support for the `ISO 8601 `_ standard\n- Timezone conversion\n- Support for ``dateutil``, ``pytz``, and ``ZoneInfo`` tzinfo objects\n- Generates time spans, ranges, floors and ceilings for time frames ranging from microsecond to year\n- Humanize dates and times with a growing list of contributed locales\n- Extensible for your own Arrow-derived types\n- Full support for PEP 484-style type hints\n\nQuick Start\n-----------\n\nInstallation\n~~~~~~~~~~~~\n\nTo install Arrow, use `pip `_ or `pipenv `_:\n\n.. code-block:: console\n\n $ pip install -U arrow\n\nExample Usage\n~~~~~~~~~~~~~\n\n.. code-block:: python\n\n >>> import arrow\n >>> arrow.get('2013-05-11T21:23:58.970460+07:00')\n \n\n >>> utc = arrow.utcnow()\n >>> utc\n \n\n >>> utc = utc.shift(hours=-1)\n >>> utc\n \n\n >>> local = utc.to('US/Pacific')\n >>> local\n \n\n >>> local.timestamp()\n 1368303838.970460\n\n >>> local.format()\n '2013-05-11 13:23:58 -07:00'\n\n >>> local.format('YYYY-MM-DD HH:mm:ss ZZ')\n '2013-05-11 13:23:58 -07:00'\n\n >>> local.humanize()\n 'an hour ago'\n\n >>> local.humanize(locale='ko-kr')\n '한시간 전'\n\n.. end-inclusion-marker-do-not-remove\n\nDocumentation\n-------------\n\nFor full documentation, please visit `arrow.readthedocs.io `_.\n\nContributing\n------------\n\nContributions are welcome for both code and localizations (adding and updating locales). Begin by gaining familiarity with the Arrow library and its features. Then, jump into contributing:\n\n#. Find an issue or feature to tackle on the `issue tracker `_. Issues marked with the `\"good first issue\" label `_ may be a great place to start!\n#. Fork `this repository `_ on GitHub and begin making changes in a branch.\n#. Add a few tests to ensure that the bug was fixed or the feature works as expected.\n#. Run the entire test suite and linting checks by running one of the following commands: ``tox && tox -e lint,docs`` (if you have `tox `_ installed) **OR** ``make build39 && make test && make lint`` (if you do not have Python 3.9 installed, replace ``build39`` with the latest Python version on your system).\n#. Submit a pull request and await feedback 😃.\n\nIf you have any questions along the way, feel free to ask them `here `_.\n\nSupport Arrow\n-------------\n\n`Open Collective `_ is an online funding platform that provides tools to raise money and share your finances with full transparency. It is the platform of choice for individuals and companies to make one-time or recurring donations directly to the project. If you are interested in making a financial contribution, please visit the `Arrow collective `_.\n\n", + "description_content_type": "text/x-rst", + "keywords": [ + "arrow", + "date", + "time", + "datetime", + "timestamp", + "timezone", + "humanize" + ], + "author_email": "Chris Smith ", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Information Technology", + "License :: OSI Approved :: Apache Software License", + "Topic :: Software Development :: Libraries :: Python Modules", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Operating System :: OS Independent" + ], + "requires_dist": [ + "python-dateutil>=2.7.0", + "types-python-dateutil>=2.8.10", + "doc8 ; extra == \"doc\"", + "sphinx>=7.0.0 ; extra == \"doc\"", + "sphinx-autobuild ; extra == \"doc\"", + "sphinx-autodoc-typehints ; extra == \"doc\"", + "sphinx_rtd_theme>=1.3.0 ; extra == \"doc\"", + "dateparser==1.* ; extra == \"test\"", + "pre-commit ; extra == \"test\"", + "pytest ; extra == \"test\"", + "pytest-cov ; extra == \"test\"", + "pytest-mock ; extra == \"test\"", + "pytz==2021.1 ; extra == \"test\"", + "simplejson==3.* ; extra == \"test\"" + ], + "requires_python": ">=3.8", + "project_url": [ + "Documentation, https://arrow.readthedocs.io", + "Issues, https://github.com/arrow-py/arrow/issues", + "Source, https://github.com/arrow-py/arrow" + ], + "provides_extra": [ + "doc", + "test" + ] + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", + "archive_info": { + "hash": "sha256=c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", + "hashes": { + "sha256": "c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "pycparser", + "version": "2.22", + "platform": [ + "Cross Platform" + ], + "summary": "C parser in Python", + "description": "\n pycparser is a complete parser of the C language, written in\n pure Python using the PLY parsing library.\n It parses C code into an AST and can serve as a front-end for\n C compilers or analysis tools.\n \n\n", + "home_page": "https://github.com/eliben/pycparser", + "author": "Eli Bendersky", + "author_email": "eliben@gmail.com", + "maintainer": "Eli Bendersky", + "license": "BSD-3-Clause", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: BSD License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" + ], + "requires_python": ">=3.8" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/c7/1b/af4f4c4f3f7339a4b7eb3c0ab13416db98f8ac09de3399129ee5fdfa282b/types_python_dateutil-2.9.0.20240316-py3-none-any.whl", + "archive_info": { + "hash": "sha256=6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b", + "hashes": { + "sha256": "6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": false, + "metadata": { + "metadata_version": "2.1", + "name": "types-python-dateutil", + "version": "2.9.0.20240316", + "summary": "Typing stubs for python-dateutil", + "description": "## Typing stubs for python-dateutil\n\nThis is a [PEP 561](https://peps.python.org/pep-0561/)\ntype stub package for the [`python-dateutil`](https://github.com/dateutil/dateutil) package.\nIt can be used by type-checking tools like\n[mypy](https://github.com/python/mypy/),\n[pyright](https://github.com/microsoft/pyright),\n[pytype](https://github.com/google/pytype/),\nPyCharm, etc. to check code that uses\n`python-dateutil`.\n\nThis version of `types-python-dateutil` aims to provide accurate annotations\nfor `python-dateutil==2.9.*`.\nThe source for this package can be found at\nhttps://github.com/python/typeshed/tree/main/stubs/python-dateutil. All fixes for\ntypes and metadata should be contributed there.\n\nThis stub package is marked as [partial](https://peps.python.org/pep-0561/#partial-stub-packages).\nIf you find that annotations are missing, feel free to contribute and help complete them.\n\n\nSee https://github.com/python/typeshed/blob/main/README.md for more details.\nThis package was generated from typeshed commit `82d84c758cbfb3ebe8bed63b39354da21e0d3794` and was tested\nwith mypy 1.9.0, pyright 1.1.354, and\npytype 2024.3.11.\n", + "description_content_type": "text/markdown", + "home_page": "https://github.com/python/typeshed", + "license": "Apache-2.0 license", + "classifier": [ + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Typing :: Stubs Only" + ], + "requires_python": ">=3.8", + "project_url": [ + "GitHub, https://github.com/python/typeshed", + "Changes, https://github.com/typeshed-internal/stub_uploader/blob/main/data/changelogs/python-dateutil.md", + "Issue tracker, https://github.com/python/typeshed/issues", + "Chat, https://gitter.im/python/typing" + ] + } + } + ], + "environment": { + "implementation_name": "cpython", + "implementation_version": "3.12.3", + "os_name": "nt", + "platform_machine": "AMD64", + "platform_release": "11", + "platform_system": "Windows", + "platform_version": "10.0.22631", + "python_full_version": "3.12.3", + "platform_python_implementation": "CPython", + "python_version": "3.12", + "sys_platform": "win32" + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_multi_pkg.json b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_multi_pkg.json new file mode 100644 index 000000000..8e969d97a --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_multi_pkg.json @@ -0,0 +1,114 @@ +{ + "version": "1", + "pip_version": "24.0", + "install": [ + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "hashes": { + "sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": true, + "metadata": { + "metadata_version": "2.1", + "name": "six", + "version": "1.16.0", + "platform": [ + "UNKNOWN" + ], + "summary": "Python 2 and 3 compatibility utilities", + "description": ".. image:: https://img.shields.io/pypi/v/six.svg\n :target: https://pypi.org/project/six/\n :alt: six on PyPI\n\n.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master\n :target: https://travis-ci.org/benjaminp/six\n :alt: six on TravisCI\n\n.. image:: https://readthedocs.org/projects/six/badge/?version=latest\n :target: https://six.readthedocs.io/\n :alt: six's documentation on Read the Docs\n\n.. image:: https://img.shields.io/badge/license-MIT-green.svg\n :target: https://github.com/benjaminp/six/blob/master/LICENSE\n :alt: MIT License badge\n\nSix is a Python 2 and 3 compatibility library. It provides utility functions\nfor smoothing over the differences between the Python versions with the goal of\nwriting Python code that is compatible on both Python versions. See the\ndocumentation for more information on what is provided.\n\nSix supports Python 2.7 and 3.3+. It is contained in only one Python\nfile, so it can be easily copied into your project. (The copyright and license\nnotice must be retained.)\n\nOnline documentation is at https://six.readthedocs.io/.\n\nBugs can be reported to https://github.com/benjaminp/six. The code can also\nbe found there.\n\n\n", + "home_page": "https://github.com/benjaminp/six", + "author": "Benjamin Peterson", + "author_email": "benjamin@python.org", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + } + }, + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", + "hashes": { + "sha256": "a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": true, + "metadata": { + "metadata_version": "2.1", + "name": "python-dateutil", + "version": "2.9.0.post0", + "summary": "Extensions to the standard Python datetime module", + "description": "dateutil - powerful extensions to datetime\n==========================================\n\n|pypi| |support| |licence|\n\n|gitter| |readthedocs|\n\n|travis| |appveyor| |pipelines| |coverage|\n\n.. |pypi| image:: https://img.shields.io/pypi/v/python-dateutil.svg?style=flat-square\n :target: https://pypi.org/project/python-dateutil/\n :alt: pypi version\n\n.. |support| image:: https://img.shields.io/pypi/pyversions/python-dateutil.svg?style=flat-square\n :target: https://pypi.org/project/python-dateutil/\n :alt: supported Python version\n\n.. |travis| image:: https://img.shields.io/travis/dateutil/dateutil/master.svg?style=flat-square&label=Travis%20Build\n :target: https://travis-ci.org/dateutil/dateutil\n :alt: travis build status\n\n.. |appveyor| image:: https://img.shields.io/appveyor/ci/dateutil/dateutil/master.svg?style=flat-square&logo=appveyor\n :target: https://ci.appveyor.com/project/dateutil/dateutil\n :alt: appveyor build status\n\n.. |pipelines| image:: https://dev.azure.com/pythondateutilazure/dateutil/_apis/build/status/dateutil.dateutil?branchName=master\n :target: https://dev.azure.com/pythondateutilazure/dateutil/_build/latest?definitionId=1&branchName=master\n :alt: azure pipelines build status\n\n.. |coverage| image:: https://codecov.io/gh/dateutil/dateutil/branch/master/graphs/badge.svg?branch=master\n :target: https://codecov.io/gh/dateutil/dateutil?branch=master\n :alt: Code coverage\n\n.. |gitter| image:: https://badges.gitter.im/dateutil/dateutil.svg\n :alt: Join the chat at https://gitter.im/dateutil/dateutil\n :target: https://gitter.im/dateutil/dateutil\n\n.. |licence| image:: https://img.shields.io/pypi/l/python-dateutil.svg?style=flat-square\n :target: https://pypi.org/project/python-dateutil/\n :alt: licence\n\n.. |readthedocs| image:: https://img.shields.io/readthedocs/dateutil/latest.svg?style=flat-square&label=Read%20the%20Docs\n :alt: Read the documentation at https://dateutil.readthedocs.io/en/latest/\n :target: https://dateutil.readthedocs.io/en/latest/\n\nThe `dateutil` module provides powerful extensions to\nthe standard `datetime` module, available in Python.\n\nInstallation\n============\n`dateutil` can be installed from PyPI using `pip` (note that the package name is\ndifferent from the importable name)::\n\n pip install python-dateutil\n\nDownload\n========\ndateutil is available on PyPI\nhttps://pypi.org/project/python-dateutil/\n\nThe documentation is hosted at:\nhttps://dateutil.readthedocs.io/en/stable/\n\nCode\n====\nThe code and issue tracker are hosted on GitHub:\nhttps://github.com/dateutil/dateutil/\n\nFeatures\n========\n\n* Computing of relative deltas (next month, next year,\n next Monday, last week of month, etc);\n* Computing of relative deltas between two given\n date and/or datetime objects;\n* Computing of dates based on very flexible recurrence rules,\n using a superset of the `iCalendar `_\n specification. Parsing of RFC strings is supported as well.\n* Generic parsing of dates in almost any string format;\n* Timezone (tzinfo) implementations for tzfile(5) format\n files (/etc/localtime, /usr/share/zoneinfo, etc), TZ\n environment string (in all known formats), iCalendar\n format files, given ranges (with help from relative deltas),\n local machine timezone, fixed offset timezone, UTC timezone,\n and Windows registry-based time zones.\n* Internal up-to-date world timezone information based on\n Olson's database.\n* Computing of Easter Sunday dates for any given year,\n using Western, Orthodox or Julian algorithms;\n* A comprehensive test suite.\n\nQuick example\n=============\nHere's a snapshot, just to give an idea about the power of the\npackage. For more examples, look at the documentation.\n\nSuppose you want to know how much time is left, in\nyears/months/days/etc, before the next easter happening on a\nyear with a Friday 13th in August, and you want to get today's\ndate out of the \"date\" unix system command. Here is the code:\n\n.. code-block:: python3\n\n >>> from dateutil.relativedelta import *\n >>> from dateutil.easter import *\n >>> from dateutil.rrule import *\n >>> from dateutil.parser import *\n >>> from datetime import *\n >>> now = parse(\"Sat Oct 11 17:13:46 UTC 2003\")\n >>> today = now.date()\n >>> year = rrule(YEARLY,dtstart=now,bymonth=8,bymonthday=13,byweekday=FR)[0].year\n >>> rdelta = relativedelta(easter(year), today)\n >>> print(\"Today is: %s\" % today)\n Today is: 2003-10-11\n >>> print(\"Year with next Aug 13th on a Friday is: %s\" % year)\n Year with next Aug 13th on a Friday is: 2004\n >>> print(\"How far is the Easter of that year: %s\" % rdelta)\n How far is the Easter of that year: relativedelta(months=+6)\n >>> print(\"And the Easter of that year is: %s\" % (today+rdelta))\n And the Easter of that year is: 2004-04-11\n\nBeing exactly 6 months ahead was **really** a coincidence :)\n\nContributing\n============\n\nWe welcome many types of contributions - bug reports, pull requests (code, infrastructure or documentation fixes). For more information about how to contribute to the project, see the ``CONTRIBUTING.md`` file in the repository.\n\n\nAuthor\n======\nThe dateutil module was written by Gustavo Niemeyer \nin 2003.\n\nIt is maintained by:\n\n* Gustavo Niemeyer 2003-2011\n* Tomi Pieviläinen 2012-2014\n* Yaron de Leeuw 2014-2016\n* Paul Ganssle 2015-\n\nStarting with version 2.4.1 and running until 2.8.2, all source and binary\ndistributions will be signed by a PGP key that has, at the very least, been\nsigned by the key which made the previous release. A table of release signing\nkeys can be found below:\n\n=========== ============================\nReleases Signing key fingerprint\n=========== ============================\n2.4.1-2.8.2 `6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB`_\n=========== ============================\n\nNew releases *may* have signed tags, but binary and source distributions\nuploaded to PyPI will no longer have GPG signatures attached.\n\nContact\n=======\nOur mailing list is available at `dateutil@python.org `_. As it is hosted by the PSF, it is subject to the `PSF code of\nconduct `_.\n\nLicense\n=======\n\nAll contributions after December 1, 2017 released under dual license - either `Apache 2.0 License `_ or the `BSD 3-Clause License `_. Contributions before December 1, 2017 - except those those explicitly relicensed - are released only under the BSD 3-Clause License.\n\n\n.. _6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB:\n https://pgp.mit.edu/pks/lookup?op=vindex&search=0xCD54FCE3D964BEFB\n", + "description_content_type": "text/x-rst", + "home_page": "https://github.com/dateutil/dateutil", + "author": "Gustavo Niemeyer", + "author_email": "gustavo@niemeyer.net", + "maintainer": "Paul Ganssle", + "maintainer_email": "dateutil@python.org", + "license": "Dual License", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Libraries" + ], + "requires_dist": [ + "six >=1.5" + ], + "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7", + "project_url": [ + "Documentation, https://dateutil.readthedocs.io/en/stable/", + "Source, https://github.com/dateutil/dateutil" + ] + } + } + ], + "environment": { + "implementation_name": "cpython", + "implementation_version": "3.12.3", + "os_name": "nt", + "platform_machine": "AMD64", + "platform_release": "11", + "platform_system": "Windows", + "platform_version": "10.0.22631", + "python_full_version": "3.12.3", + "platform_python_implementation": "CPython", + "python_version": "3.12", + "sys_platform": "win32" + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_single_pkg.json b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_single_pkg.json new file mode 100644 index 000000000..0cb6bdc43 --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_single_pkg.json @@ -0,0 +1,57 @@ +{ + "version": "1", + "pip_version": "24.0", + "install": [ + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "hashes": { + "sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": true, + "metadata": { + "metadata_version": "2.1", + "name": "six", + "version": "1.16.0", + "platform": [ + "UNKNOWN" + ], + "summary": "Python 2 and 3 compatibility utilities", + "description": ".. image:: https://img.shields.io/pypi/v/six.svg\n :target: https://pypi.org/project/six/\n :alt: six on PyPI\n\n.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master\n :target: https://travis-ci.org/benjaminp/six\n :alt: six on TravisCI\n\n.. image:: https://readthedocs.org/projects/six/badge/?version=latest\n :target: https://six.readthedocs.io/\n :alt: six's documentation on Read the Docs\n\n.. image:: https://img.shields.io/badge/license-MIT-green.svg\n :target: https://github.com/benjaminp/six/blob/master/LICENSE\n :alt: MIT License badge\n\nSix is a Python 2 and 3 compatibility library. It provides utility functions\nfor smoothing over the differences between the Python versions with the goal of\nwriting Python code that is compatible on both Python versions. See the\ndocumentation for more information on what is provided.\n\nSix supports Python 2.7 and 3.3+. It is contained in only one Python\nfile, so it can be easily copied into your project. (The copyright and license\nnotice must be retained.)\n\nOnline documentation is at https://six.readthedocs.io/.\n\nBugs can be reported to https://github.com/benjaminp/six. The code can also\nbe found there.\n\n\n", + "home_page": "https://github.com/benjaminp/six", + "author": "Benjamin Peterson", + "author_email": "benjamin@python.org", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + } + } + ], + "environment": { + "implementation_name": "cpython", + "implementation_version": "3.12.3", + "os_name": "nt", + "platform_machine": "AMD64", + "platform_release": "11", + "platform_system": "Windows", + "platform_version": "10.0.22631", + "python_full_version": "3.12.3", + "platform_python_implementation": "CPython", + "python_version": "3.12", + "sys_platform": "win32" + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_single_pkg_bad_version.json b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_single_pkg_bad_version.json new file mode 100644 index 000000000..998b83e1d --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/Mocks/pip_report_single_pkg_bad_version.json @@ -0,0 +1,57 @@ +{ + "version": "2", + "pip_version": "24.0", + "install": [ + { + "download_info": { + "url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", + "archive_info": { + "hash": "sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", + "hashes": { + "sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + } + } + }, + "is_direct": false, + "is_yanked": false, + "requested": true, + "metadata": { + "metadata_version": "2.1", + "name": "six", + "version": "1.16.0", + "platform": [ + "UNKNOWN" + ], + "summary": "Python 2 and 3 compatibility utilities", + "description": ".. image:: https://img.shields.io/pypi/v/six.svg\n :target: https://pypi.org/project/six/\n :alt: six on PyPI\n\n.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master\n :target: https://travis-ci.org/benjaminp/six\n :alt: six on TravisCI\n\n.. image:: https://readthedocs.org/projects/six/badge/?version=latest\n :target: https://six.readthedocs.io/\n :alt: six's documentation on Read the Docs\n\n.. image:: https://img.shields.io/badge/license-MIT-green.svg\n :target: https://github.com/benjaminp/six/blob/master/LICENSE\n :alt: MIT License badge\n\nSix is a Python 2 and 3 compatibility library. It provides utility functions\nfor smoothing over the differences between the Python versions with the goal of\nwriting Python code that is compatible on both Python versions. See the\ndocumentation for more information on what is provided.\n\nSix supports Python 2.7 and 3.3+. It is contained in only one Python\nfile, so it can be easily copied into your project. (The copyright and license\nnotice must be retained.)\n\nOnline documentation is at https://six.readthedocs.io/.\n\nBugs can be reported to https://github.com/benjaminp/six. The code can also\nbe found there.\n\n\n", + "home_page": "https://github.com/benjaminp/six", + "author": "Benjamin Peterson", + "author_email": "benjamin@python.org", + "license": "MIT", + "classifier": [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Topic :: Software Development :: Libraries", + "Topic :: Utilities" + ], + "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + } + } + ], + "environment": { + "implementation_name": "cpython", + "implementation_version": "3.12.3", + "os_name": "nt", + "platform_machine": "AMD64", + "platform_release": "11", + "platform_system": "Windows", + "platform_version": "10.0.22631", + "python_full_version": "3.12.3", + "platform_python_implementation": "CPython", + "python_version": "3.12", + "sys_platform": "win32" + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PipCommandServiceTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PipCommandServiceTests.cs new file mode 100644 index 000000000..73d983ea7 --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PipCommandServiceTests.cs @@ -0,0 +1,469 @@ +namespace Microsoft.ComponentDetection.Detectors.Tests; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.ComponentDetection.Common; +using Microsoft.ComponentDetection.Contracts; +using Microsoft.ComponentDetection.Detectors.Pip; +using Microsoft.ComponentDetection.Detectors.Tests.Mocks; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +[TestClass] +[TestCategory("Governance/All")] +[TestCategory("Governance/ComponentDetection")] +public class PipCommandServiceTests +{ + private readonly Mock commandLineInvokationService; + private readonly Mock envVarService; + private readonly Mock fileUtilityService; + private readonly Mock> pathLogger; + private readonly Mock> logger; + private readonly IPathUtilityService pathUtilityService; + + public PipCommandServiceTests() + { + this.commandLineInvokationService = new Mock(); + this.pathLogger = new Mock>(); + this.logger = new Mock>(); + this.pathUtilityService = new PathUtilityService(this.pathLogger.Object); + this.envVarService = new Mock(); + this.fileUtilityService = new Mock(); + } + + [TestMethod] + public async Task PipCommandService_ReturnsTrueWhenPipExistsAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("pip", It.IsAny>(), "--version")).ReturnsAsync(true); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + (await service.PipExistsAsync()).Should().BeTrue(); + } + + [TestMethod] + public async Task PipCommandService_ReturnsFalseWhenPipExistsAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("pip", It.IsAny>(), "--version")).ReturnsAsync(false); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + (await service.PipExistsAsync()).Should().BeFalse(); + } + + [TestMethod] + public async Task PipCommandService_ReturnsTrueWhenPipExistsForAPathAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("testPath", It.IsAny>(), "--version")).ReturnsAsync(true); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + (await service.PipExistsAsync("testPath")).Should().BeTrue(); + } + + [TestMethod] + public async Task PipCommandService_ReturnsFalseWhenPipExistsForAPathAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("testPath", It.IsAny>(), "--version")).ReturnsAsync(false); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + (await service.PipExistsAsync("testPath")).Should().BeFalse(); + } + + [TestMethod] + public async Task PipCommandService_BadVersion_ReturnsNullAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync( + "pip", + It.IsAny>(), + "--version")) + .ReturnsAsync(true); + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "pip", + It.IsAny>(), + "--version")) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = string.Empty }); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + var semVer = await service.GetPipVersionAsync(); + semVer.Should().BeNull(); + } + + [TestMethod] + public async Task PipCommandService_BadVersionString_ReturnsNullAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync( + "pip", + It.IsAny>(), + "--version")) + .ReturnsAsync(true); + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "pip", + It.IsAny>(), + "--version")) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = "this is not a valid output" }); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + var semVer = await service.GetPipVersionAsync(); + semVer.Should().BeNull(); + } + + [TestMethod] + public async Task PipCommandService_ReturnsVersionAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync( + "pip", + It.IsAny>(), + "--version")) + .ReturnsAsync(true); + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "pip", + It.IsAny>(), + "--version")) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = "pip 20.0.2 from c:\\python\\lib\\site-packages\\pip (python 3.8)" }); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + var semVer = await service.GetPipVersionAsync(); + semVer.Major.Should().Be(20); + semVer.Minor.Should().Be(0); + semVer.Build.Should().Be(2); + } + + [TestMethod] + public async Task PipCommandService_ReturnsVersion_SimpleAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync( + "pip", + It.IsAny>(), + "--version")) + .ReturnsAsync(true); + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "pip", + It.IsAny>(), + "--version")) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = "pip 24.0 from c:\\python\\lib\\site-packages\\pip (python 3.8)" }); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + var semVer = await service.GetPipVersionAsync(); + semVer.Major.Should().Be(24); + semVer.Minor.Should().Be(0); + } + + [TestMethod] + public async Task PipCommandService_ReturnsVersionForAPathAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync( + "testPath", + It.IsAny>(), + "--version")) + .ReturnsAsync(true); + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "testPath", + It.IsAny>(), + "--version")) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = "pip 20.0.2 from c:\\python\\lib\\site-packages\\pip (python 3.8)" }); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + var semVer = await service.GetPipVersionAsync("testPath"); + semVer.Major.Should().Be(20); + semVer.Minor.Should().Be(0); + semVer.Build.Should().Be(2); + } + + [TestMethod] + public async Task PipCommandService_GeneratesReport_RequirementsTxt_CorrectlyAsync() + { + var testPath = Path.Join(Directory.GetCurrentDirectory(), string.Join(Guid.NewGuid().ToString(), ".txt")); + + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("pip", It.IsAny>(), "--version")).ReturnsAsync(true); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "pip", + It.IsAny>(), + It.Is(d => d.FullName.Contains(Directory.GetCurrentDirectory(), StringComparison.OrdinalIgnoreCase)), + It.Is(s => s.Contains("requirements.txt", StringComparison.OrdinalIgnoreCase)))) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdErr = string.Empty, StdOut = string.Empty }) + .Verifiable(); + + this.fileUtilityService.Setup(x => x.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync(TestResources.pip_report_single_pkg); + + var (report, reportFile) = await service.GenerateInstallationReportAsync(testPath); + + // the file shouldn't exist since we're not writing to it in the test + reportFile.Should().NotBeNull(); + reportFile.Exists.Should().Be(false); + + // validate report parameters + report.Should().NotBeNull(); + report.Version.Should().Be("1"); + report.InstallItems.Should().NotBeNull(); + report.InstallItems.Should().ContainSingle(); + + // validate packages + report.InstallItems[0].Requested.Should().BeTrue(); + report.InstallItems[0].Metadata.Name.Should().Be("six"); + report.InstallItems[0].Metadata.Version.Should().Be("1.16.0"); + report.InstallItems[0].Metadata.License.Should().Be("MIT"); + report.InstallItems[0].Metadata.Author.Should().Be("Benjamin Peterson"); + report.InstallItems[0].Metadata.AuthorEmail.Should().Be("benjamin@python.org"); + report.InstallItems[0].Metadata.Maintainer.Should().BeNullOrEmpty(); + report.InstallItems[0].Metadata.MaintainerEmail.Should().BeNullOrEmpty(); + + this.commandLineInvokationService.Verify(); + } + + [TestMethod] + public async Task PipCommandService_GeneratesReport_SetupPy_CorrectlyAsync() + { + var testPath = Path.Join(Directory.GetCurrentDirectory(), string.Join(Guid.NewGuid().ToString(), ".py")); + + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("pip", It.IsAny>(), "--version")).ReturnsAsync(true); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "pip", + It.IsAny>(), + It.Is(d => d.FullName.Contains(Directory.GetCurrentDirectory(), StringComparison.OrdinalIgnoreCase)), + It.Is(s => s.Contains("-e .", StringComparison.OrdinalIgnoreCase)))) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdErr = string.Empty, StdOut = string.Empty }) + .Verifiable(); + + this.fileUtilityService.Setup(x => x.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync(TestResources.pip_report_single_pkg); + + var (report, reportFile) = await service.GenerateInstallationReportAsync(testPath); + + // the file shouldn't exist since we're not writing to it in the test + reportFile.Should().NotBeNull(); + reportFile.Exists.Should().Be(false); + + // validate report parameters + report.Should().NotBeNull(); + report.Version.Should().Be("1"); + report.InstallItems.Should().NotBeNull(); + report.InstallItems.Should().ContainSingle(); + + // validate packages + report.InstallItems[0].Requested.Should().BeTrue(); + report.InstallItems[0].Metadata.Name.Should().Be("six"); + report.InstallItems[0].Metadata.Version.Should().Be("1.16.0"); + report.InstallItems[0].Metadata.License.Should().Be("MIT"); + report.InstallItems[0].Metadata.Author.Should().Be("Benjamin Peterson"); + report.InstallItems[0].Metadata.AuthorEmail.Should().Be("benjamin@python.org"); + report.InstallItems[0].Metadata.Maintainer.Should().BeNullOrEmpty(); + report.InstallItems[0].Metadata.MaintainerEmail.Should().BeNullOrEmpty(); + + this.commandLineInvokationService.Verify(); + } + + [TestMethod] + public async Task PipCommandService_GeneratesReport_MultiRequirementsTxt_CorrectlyAsync() + { + var testPath = Path.Join(Directory.GetCurrentDirectory(), string.Join(Guid.NewGuid().ToString(), ".txt")); + + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("pip", It.IsAny>(), "--version")).ReturnsAsync(true); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "pip", + It.IsAny>(), + It.Is(d => d.FullName.Contains(Directory.GetCurrentDirectory(), StringComparison.OrdinalIgnoreCase)), + It.Is(s => s.Contains("requirements.txt", StringComparison.OrdinalIgnoreCase)))) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdErr = string.Empty, StdOut = string.Empty }) + .Verifiable(); + + this.fileUtilityService.Setup(x => x.ReadAllTextAsync(It.IsAny())) + .ReturnsAsync(TestResources.pip_report_multi_pkg); + + var (report, reportFile) = await service.GenerateInstallationReportAsync(testPath); + + // the file shouldn't exist since we're not writing to it in the test + reportFile.Should().NotBeNull(); + reportFile.Exists.Should().Be(false); + + // validate report parameters + report.Should().NotBeNull(); + report.Version.Should().Be("1"); + report.InstallItems.Should().NotBeNull(); + report.InstallItems.Should().HaveCount(2); + + // validate packages + report.InstallItems[0].Requested.Should().BeTrue(); + report.InstallItems[0].Metadata.Name.Should().Be("six"); + report.InstallItems[0].Metadata.Version.Should().Be("1.16.0"); + report.InstallItems[0].Metadata.License.Should().Be("MIT"); + report.InstallItems[0].Metadata.Author.Should().Be("Benjamin Peterson"); + report.InstallItems[0].Metadata.AuthorEmail.Should().Be("benjamin@python.org"); + report.InstallItems[0].Metadata.Maintainer.Should().BeNullOrEmpty(); + report.InstallItems[0].Metadata.MaintainerEmail.Should().BeNullOrEmpty(); + + report.InstallItems[1].Requested.Should().BeTrue(); + report.InstallItems[1].Metadata.Name.Should().Be("python-dateutil"); + report.InstallItems[1].Metadata.Version.Should().Be("2.9.0.post0"); + report.InstallItems[1].Metadata.License.Should().Be("Dual License"); + report.InstallItems[1].Metadata.Author.Should().Be("Gustavo Niemeyer"); + report.InstallItems[1].Metadata.AuthorEmail.Should().Be("gustavo@niemeyer.net"); + report.InstallItems[1].Metadata.Maintainer.Should().Be("Paul Ganssle"); + report.InstallItems[1].Metadata.MaintainerEmail.Should().Be("dateutil@python.org"); + + this.commandLineInvokationService.Verify(); + } + + [TestMethod] + public async Task PipCommandService_GeneratesReport_BadFile_FailsAsync() + { + var testPath = Path.Join(Directory.GetCurrentDirectory(), string.Join(Guid.NewGuid().ToString(), ".randomfile")); + + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("pip", It.IsAny>(), "--version")).ReturnsAsync(true); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + var (report, reportFile) = await service.GenerateInstallationReportAsync(testPath); + + // the file shouldn't exist since we're not writing to it in the test + reportFile.Should().BeNull(); + + // validate report parameters + report.Should().NotBeNull(); + report.Version.Should().BeNull(); + report.InstallItems.Should().BeNull(); + } + + [TestMethod] + public async Task PipCommandService_GeneratesReport_EmptyPath_FailsAsync() + { + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("pip", It.IsAny>(), "--version")).ReturnsAsync(true); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + var (report, reportFile) = await service.GenerateInstallationReportAsync(string.Empty); + + // the file shouldn't exist since we're not writing to it in the test + reportFile.Should().BeNull(); + + // validate report parameters + report.Should().NotBeNull(); + report.Version.Should().BeNull(); + report.InstallItems.Should().BeNull(); + } + + [TestMethod] + public async Task PipCommandService_GeneratesReport_RequirementsTxt_NonZeroExitAsync() + { + var testPath = Path.Join(Directory.GetCurrentDirectory(), string.Join(Guid.NewGuid().ToString(), ".txt")); + + this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("pip", It.IsAny>(), "--version")).ReturnsAsync(true); + + var service = new PipCommandService( + this.commandLineInvokationService.Object, + this.pathUtilityService, + this.fileUtilityService.Object, + this.envVarService.Object, + this.logger.Object); + + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync( + "pip", + It.IsAny>(), + It.Is(d => d.FullName.Contains(Directory.GetCurrentDirectory(), StringComparison.OrdinalIgnoreCase)), + It.Is(s => s.Contains("requirements.txt", StringComparison.OrdinalIgnoreCase)))) + .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 1, StdErr = "TestFail", StdOut = string.Empty }) + .Verifiable(); + + var (report, reportFile) = await service.GenerateInstallationReportAsync(testPath); + + // the file shouldn't exist since we're not writing to it in the test + reportFile.Should().BeNull(); + + // validate report parameters + report.Should().NotBeNull(); + report.Version.Should().BeNull(); + report.InstallItems.Should().BeNull(); + + this.commandLineInvokationService.Verify(); + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PipComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PipComponentDetectorTests.cs index 066d1e1a5..8374abd55 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PipComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PipComponentDetectorTests.cs @@ -14,7 +14,6 @@ namespace Microsoft.ComponentDetection.Detectors.Tests; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using Newtonsoft.Json; [TestClass] public class PipComponentDetectorTests : BaseDetectorTest @@ -231,12 +230,12 @@ public async Task TestPipDetector_ComponentRecorderAsync() x => x.Id == rootId); } - this.CheckChild(componentRecorder, "red 0.2 - pip", new[] { "a 1.0 - pip", "c 1.0 - pip", }); - this.CheckChild(componentRecorder, "green 1.3 - pip", new[] { "b 2.1 - pip", }); - this.CheckChild(componentRecorder, "blue 0.4 - pip", new[] { "c 1.0 - pip", }); - this.CheckChild(componentRecorder, "cat 1.8 - pip", new[] { "b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip", }); - this.CheckChild(componentRecorder, "lion 3.8 - pip", new[] { "b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip", }); - this.CheckChild(componentRecorder, "dog 2.1 - pip", new[] { "c 1.0 - pip", }); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "red 0.2 - pip", new[] { "a 1.0 - pip", "c 1.0 - pip", }); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "green 1.3 - pip", new[] { "b 2.1 - pip", }); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "blue 0.4 - pip", new[] { "c 1.0 - pip", }); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "cat 1.8 - pip", new[] { "b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip", }); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "lion 3.8 - pip", new[] { "b 2.1 - pip", "c 1.0 - pip", "d 1.9 - pip", }); + ComponentRecorderTestUtilities.CheckChild(componentRecorder, "dog 2.1 - pip", new[] { "c 1.0 - pip", }); var graphsByLocations = componentRecorder.GetDependencyGraphsByLocation(); graphsByLocations.Should().HaveCount(2); @@ -254,7 +253,7 @@ public async Task TestPipDetector_ComponentRecorderAsync() var graph1 = graphsByLocations[file1]; graph1ComponentsWithDeps.Keys.Take(2).All(graph1.IsComponentExplicitlyReferenced).Should().BeTrue(); graph1ComponentsWithDeps.Keys.Skip(2).Should().OnlyContain(a => !graph1.IsComponentExplicitlyReferenced(a)); - this.CheckGraphStructure(graph1, graph1ComponentsWithDeps); + ComponentRecorderTestUtilities.CheckGraphStructure(graph1, graph1ComponentsWithDeps); var graph2ComponentsWithDeps = new Dictionary { @@ -271,41 +270,7 @@ public async Task TestPipDetector_ComponentRecorderAsync() var graph2 = graphsByLocations[file2]; graph2ComponentsWithDeps.Keys.Take(3).All(graph2.IsComponentExplicitlyReferenced).Should().BeTrue(); graph2ComponentsWithDeps.Keys.Skip(3).Should().OnlyContain(a => !graph2.IsComponentExplicitlyReferenced(a)); - this.CheckGraphStructure(graph2, graph2ComponentsWithDeps); - } - - private void CheckGraphStructure(IDependencyGraph graph, Dictionary graphComponentsWithDeps) - { - var graphComponents = graph.GetComponents().ToArray(); - graphComponents.Should().HaveCount( - graphComponentsWithDeps.Keys.Count, - $"Expected {graphComponentsWithDeps.Keys.Count} component to be recorded but got {graphComponents.Length} instead!"); - - foreach (var componentId in graphComponentsWithDeps.Keys) - { - graphComponents.Should().Contain( - componentId, $"Component `{componentId}` not recorded!"); - - var recordedDeps = graph.GetDependenciesForComponent(componentId).ToArray(); - var expectedDeps = graphComponentsWithDeps[componentId]; - - recordedDeps.Should().HaveCount( - expectedDeps.Length, - $"Count missmatch of expected dependencies ({JsonConvert.SerializeObject(expectedDeps)}) and recorded dependencies ({JsonConvert.SerializeObject(recordedDeps)}) for `{componentId}`!"); - - foreach (var expectedDep in expectedDeps) - { - recordedDeps.Should().Contain( - expectedDep, $"Expected `{expectedDep}` in the list of dependencies for `{componentId}` but only recorded: {JsonConvert.SerializeObject(recordedDeps)}"); - } - } - } - - private void CheckChild(IComponentRecorder recorder, string childId, string[] parentIds) - { - recorder.AssertAllExplicitlyReferencedComponents( - childId, - parentIds.Select(parentId => new Func(x => x.Id == parentId)).ToArray()); + ComponentRecorderTestUtilities.CheckGraphStructure(graph2, graph2ComponentsWithDeps); } private List<(string PackageString, GitComponent Component)> ToGitTuple(IList components) diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportComponentDetectorTests.cs new file mode 100644 index 000000000..e545df67f --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportComponentDetectorTests.cs @@ -0,0 +1,402 @@ +namespace Microsoft.ComponentDetection.Detectors.Tests; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.ComponentDetection.Contracts; +using Microsoft.ComponentDetection.Contracts.TypedComponent; +using Microsoft.ComponentDetection.Detectors.Pip; +using Microsoft.ComponentDetection.Detectors.Tests.Mocks; +using Microsoft.ComponentDetection.Detectors.Tests.Utilities; +using Microsoft.ComponentDetection.TestsUtilities; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Newtonsoft.Json; + +[TestClass] +public class PipReportComponentDetectorTests : BaseDetectorTest +{ + private readonly Mock pipCommandService; + private readonly Mock> mockLogger; + + private readonly PipInstallationReport singlePackageReport; + private readonly PipInstallationReport singlePackageReportBadVersion; + private readonly PipInstallationReport multiPackageReport; + private readonly PipInstallationReport jupyterPackageReport; + + public PipReportComponentDetectorTests() + { + this.pipCommandService = new Mock(); + this.DetectorTestUtility.AddServiceMock(this.pipCommandService); + + this.mockLogger = new Mock>(); + this.DetectorTestUtility.AddServiceMock(this.mockLogger); + + this.pipCommandService.Setup(x => x.PipExistsAsync(It.IsAny())).ReturnsAsync(true); + this.pipCommandService.Setup(x => x.GetPipVersionAsync(It.IsAny())) + .ReturnsAsync(new Version(23, 0, 0)); + + this.singlePackageReport = JsonConvert.DeserializeObject(TestResources.pip_report_single_pkg); + this.singlePackageReportBadVersion = JsonConvert.DeserializeObject(TestResources.pip_report_single_pkg_bad_version); + this.multiPackageReport = JsonConvert.DeserializeObject(TestResources.pip_report_multi_pkg); + this.jupyterPackageReport = JsonConvert.DeserializeObject(TestResources.pip_report_jupyterlab); + } + + [TestMethod] + public async Task TestPipReportDetector_PipNotInstalledAsync() + { + this.mockLogger.Setup(x => x.Log( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + (Func)It.IsAny())); + + this.DetectorTestUtility.AddServiceMock(this.mockLogger); + + this.pipCommandService.Setup(x => x.PipExistsAsync(It.IsAny())).ReturnsAsync(false); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + this.mockLogger.VerifyAll(); + } + + [TestMethod] + public async Task TestPipReportDetector_PipBadVersion_Null_Async() + { + this.pipCommandService.Setup(x => x.GetPipVersionAsync(It.IsAny())) + .ReturnsAsync((Version)null); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + this.mockLogger.Verify(x => x.Log( + LogLevel.Information, + It.IsAny(), + It.Is((o, t) => o.ToString().StartsWith("PipReport: No valid pip version")), + It.IsAny(), + (Func)It.IsAny())); + } + + [TestMethod] + public async Task TestPipReportDetector_PipBadVersion_Low_Async() + { + this.pipCommandService.Setup(x => x.GetPipVersionAsync(It.IsAny())) + .ReturnsAsync(new Version(22, 1, 0)); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + this.mockLogger.Verify(x => x.Log( + LogLevel.Information, + It.IsAny(), + It.Is((o, t) => o.ToString().StartsWith("PipReport: No valid pip version")), + It.IsAny(), + (Func)It.IsAny())); + } + + [TestMethod] + public async Task TestPipReportDetector_PipInstalledNoFilesAsync() + { + var (result, componentRecorder) = await this.DetectorTestUtility.ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + } + + [TestMethod] + public async Task TestPipReportDetector_BadReportVersionAsync() + { + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync((this.singlePackageReportBadVersion, null)); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + this.mockLogger.Verify(x => x.Log( + LogLevel.Warning, + It.IsAny(), + It.Is((o, t) => o.ToString().StartsWith("PipReport: The pip installation report version")), + It.IsAny(), + (Func)It.IsAny())); + } + + [TestMethod] + public async Task TestPipReportDetector_BadReportParseVersionAsync() + { + this.singlePackageReportBadVersion.Version = "2.5"; + + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync((this.singlePackageReportBadVersion, null)); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + this.mockLogger.Verify(x => x.Log( + LogLevel.Warning, + It.IsAny(), + It.Is((o, t) => o.ToString().StartsWith("PipReport: The pip installation report version")), + It.IsAny(), + (Func)It.IsAny())); + } + + [TestMethod] + public async Task TestPipReportDetector_CatchesExceptionAsync() + { + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync(It.IsAny(), It.IsAny())) + .ThrowsAsync(new InvalidCastException()); + + var action = async () => await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .ExecuteDetectorAsync(); + await action.Should().ThrowAsync(); + + this.mockLogger.Verify(x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((o, t) => o.ToString().StartsWith("PipReport: Failure while parsing pip")), + It.IsAny(), + (Func)It.IsAny())); + } + + [TestMethod] + public async Task TestPipReportDetector_SingleComponentAsync() + { + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync((this.singlePackageReport, null)); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + this.mockLogger.Verify(x => x.Log( + LogLevel.Information, + It.IsAny(), + It.Is((o, t) => o.ToString().StartsWith("PipReport: Generating pip installation report")), + It.IsAny(), + (Func)It.IsAny())); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + detectedComponents.Should().ContainSingle(); + + var pipComponents = detectedComponents.Where(detectedComponent => detectedComponent.Component.Id.Contains("pip")).ToList(); + + var sixComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("six")).Component as PipComponent; + sixComponent.Version.Should().Be("1.16.0"); + sixComponent.Author.Should().Be("Benjamin Peterson"); + sixComponent.License.Should().Be("MIT"); + } + + [TestMethod] + public async Task TestPipReportDetector_MultiComponentAsync() + { + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync((this.multiPackageReport, null)); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + detectedComponents.Should().HaveCount(2); + + var pipComponents = detectedComponents.Where(detectedComponent => detectedComponent.Component.Id.Contains("pip")).ToList(); + + var sixComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("six")).Component as PipComponent; + sixComponent.Version.Should().Be("1.16.0"); + sixComponent.Author.Should().Be("Benjamin Peterson"); + sixComponent.License.Should().Be("MIT"); + + var dateComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("python-dateutil")).Component as PipComponent; + dateComponent.Version.Should().Be("2.9.0.post0"); + dateComponent.Author.Should().Be("Paul Ganssle"); + dateComponent.License.Should().Be("Dual License"); + } + + [TestMethod] + public async Task TestPipReportDetector_MultiComponent_Dedupe_Async() + { + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync( + It.Is(s => s.Contains("setup.py", StringComparison.OrdinalIgnoreCase)), + It.IsAny())) + .ReturnsAsync((this.multiPackageReport, null)); + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync( + It.Is(s => s.Contains("requirements.txt", StringComparison.OrdinalIgnoreCase)), + It.IsAny())) + .ReturnsAsync((this.singlePackageReport, null)); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty) + .WithFile("requirements.txt", string.Empty) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + detectedComponents.Should().HaveCount(2); + + var pipComponents = detectedComponents.Where(detectedComponent => detectedComponent.Component.Id.Contains("pip")).ToList(); + + var sixComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("six")).Component as PipComponent; + sixComponent.Version.Should().Be("1.16.0"); + sixComponent.Author.Should().Be("Benjamin Peterson"); + sixComponent.License.Should().Be("MIT"); + + var dateComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("python-dateutil")).Component as PipComponent; + dateComponent.Version.Should().Be("2.9.0.post0"); + dateComponent.Author.Should().Be("Paul Ganssle"); + dateComponent.License.Should().Be("Dual License"); + } + + [TestMethod] + public async Task TestPipReportDetector_MultiComponent_ComponentRecorder_Async() + { + const string file1 = "c:\\repo\\setup.py"; + const string file2 = "c:\\repo\\lib\\requirements.txt"; + + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync( + It.Is(s => s.Contains("setup.py", StringComparison.OrdinalIgnoreCase)), + It.IsAny())) + .ReturnsAsync((this.multiPackageReport, null)); + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync( + It.Is(s => s.Contains("requirements.txt", StringComparison.OrdinalIgnoreCase)), + It.IsAny())) + .ReturnsAsync((this.singlePackageReport, null)); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("setup.py", string.Empty, fileLocation: file1) + .WithFile("requirements.txt", string.Empty, fileLocation: file2) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + detectedComponents.Should().HaveCount(2); + + var pipComponents = detectedComponents.Where(detectedComponent => detectedComponent.Component.Id.Contains("pip")).ToList(); + + var sixComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("six")).Component as PipComponent; + sixComponent.Version.Should().Be("1.16.0"); + sixComponent.Author.Should().Be("Benjamin Peterson"); + sixComponent.License.Should().Be("MIT"); + + var dateComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("python-dateutil")).Component as PipComponent; + dateComponent.Version.Should().Be("2.9.0.post0"); + dateComponent.Author.Should().Be("Paul Ganssle"); + dateComponent.License.Should().Be("Dual License"); + + componentRecorder.AssertAllExplicitlyReferencedComponents( + "six 1.16.0 - pip", + x => x.Id.Equals("six 1.16.0 - pip", StringComparison.OrdinalIgnoreCase), + x => x.Id.Equals("python-dateutil 2.9.0.post0 - pip", StringComparison.OrdinalIgnoreCase)); + + var graphsByLocations = componentRecorder.GetDependencyGraphsByLocation(); + graphsByLocations.Should().HaveCount(2); + + var setupGraphComponentsWithDeps = new Dictionary + { + { "six 1.16.0 - pip", Array.Empty() }, + { "python-dateutil 2.9.0.post0 - pip", new[] { "six 1.16.0 - pip" } }, + }; + + var reqGraphComponentsWithDeps = new Dictionary + { + { "six 1.16.0 - pip", Array.Empty() }, + }; + + var setupGraph = graphsByLocations[file1]; + setupGraphComponentsWithDeps.Keys.All(setupGraph.IsComponentExplicitlyReferenced).Should().BeTrue(); + ComponentRecorderTestUtilities.CheckGraphStructure(setupGraph, setupGraphComponentsWithDeps); + + var reqGraph = graphsByLocations[file2]; + reqGraph.IsComponentExplicitlyReferenced(sixComponent.Id).Should().BeTrue(); + ComponentRecorderTestUtilities.CheckGraphStructure(reqGraph, reqGraphComponentsWithDeps); + } + + [TestMethod] + public async Task TestPipReportDetector_SingleRoot_ComplexGraph_ComponentRecorder_Async() + { + const string file1 = "c:\\repo\\lib\\requirements.txt"; + + this.pipCommandService.Setup(x => x.GenerateInstallationReportAsync( + It.Is(s => s.Contains("requirements.txt", StringComparison.OrdinalIgnoreCase)), + It.IsAny())) + .ReturnsAsync((this.jupyterPackageReport, null)); + + var (result, componentRecorder) = await this.DetectorTestUtility + .WithFile("requirements.txt", string.Empty, fileLocation: file1) + .ExecuteDetectorAsync(); + + result.ResultCode.Should().Be(ProcessingResultCode.Success); + + var detectedComponents = componentRecorder.GetDetectedComponents(); + detectedComponents.Should().HaveCount(89); + + var pipComponents = detectedComponents.Where(detectedComponent => detectedComponent.Component.Id.Contains("pip")).ToList(); + + var jupyterComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("jupyterlab")).Component as PipComponent; + jupyterComponent.Version.Should().Be("4.2.0"); + jupyterComponent.Author.Should().Be("Jupyter Development Team "); + jupyterComponent.License.Should().Be("BSD License"); + + componentRecorder.AssertAllExplicitlyReferencedComponents( + "jupyterlab 4.2.0 - pip", + x => x.Id.Equals("jupyterlab 4.2.0 - pip", StringComparison.OrdinalIgnoreCase)); + + // spot check some dependencies - there are too many to verify them all here + var graphsByLocations = componentRecorder.GetDependencyGraphsByLocation(); + graphsByLocations.Should().ContainSingle(); + + var jupyterGraph = graphsByLocations[file1]; + + var jupyterLabDependencies = jupyterGraph.GetDependenciesForComponent(jupyterComponent.Id); + jupyterLabDependencies.Should().HaveCount(15); + jupyterLabDependencies.Should().Contain("async-lru 2.0.4 - pip"); + jupyterLabDependencies.Should().Contain("jupyter-server 2.14.0 - pip"); + jupyterLabDependencies.Should().Contain("traitlets 5.14.3 - pip"); + jupyterLabDependencies.Should().Contain("requests 2.32.2 - pip"); + jupyterLabDependencies.Should().Contain("jupyter-lsp 2.2.5 - pip"); + + var bleachComponent = pipComponents.Single(x => ((PipComponent)x.Component).Name.Equals("bleach")).Component as PipComponent; + bleachComponent.Version.Should().Be("6.1.0"); + bleachComponent.Author.Should().Be("Will Kahn-Greene"); + bleachComponent.License.Should().Be("Apache Software License"); + + var bleachDependencies = jupyterGraph.GetDependenciesForComponent(bleachComponent.Id); + bleachDependencies.Should().HaveCount(3); + bleachDependencies.Should().Contain("six 1.16.0 - pip"); + bleachDependencies.Should().Contain("webencodings 0.5.1 - pip"); + bleachDependencies.Should().Contain("tinycss2 1.3.0 - pip"); + + ComponentRecorderTestUtilities.CheckChild( + componentRecorder, + "async-lru 2.0.4 - pip", + new[] { "jupyterlab 4.2.0 - pip" }); + + ComponentRecorderTestUtilities.CheckChild( + componentRecorder, + "tinycss2 1.3.0 - pip", + new[] { "jupyterlab 4.2.0 - pip" }); + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportUtilitiesTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportUtilitiesTests.cs new file mode 100644 index 000000000..ee1b6ff8a --- /dev/null +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PipReportUtilitiesTests.cs @@ -0,0 +1,31 @@ +namespace Microsoft.ComponentDetection.Detectors.Tests; + +using FluentAssertions; +using Microsoft.ComponentDetection.Detectors.Pip; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +[TestCategory("Governance/All")] +[TestCategory("Governance/ComponentDetection")] +public class PipReportUtilitiesTests +{ + [TestInitialize] + public void TestInitialize() + { + } + + [TestMethod] + public void NormalizePackageName_ExpectedEquivalent() + { + // Example test cases from https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization + const string normalizedForm = "friendly-bard"; + + PipReportUtilities.NormalizePackageNameFormat("friendly-bard").Should().Be(normalizedForm); + PipReportUtilities.NormalizePackageNameFormat("Friendly-Bard").Should().Be(normalizedForm); + PipReportUtilities.NormalizePackageNameFormat("FRIENDLY-BARD").Should().Be(normalizedForm); + PipReportUtilities.NormalizePackageNameFormat("friendly.bard").Should().Be(normalizedForm); + PipReportUtilities.NormalizePackageNameFormat("friendly_bard").Should().Be(normalizedForm); + PipReportUtilities.NormalizePackageNameFormat("friendly--bard").Should().Be(normalizedForm); + PipReportUtilities.NormalizePackageNameFormat("FrIeNdLy-._.-bArD").Should().Be(normalizedForm); + } +} diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/PythonCommandServiceTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/PythonCommandServiceTests.cs index d3736b677..6bcc357a5 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/PythonCommandServiceTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/PythonCommandServiceTests.cs @@ -6,9 +6,11 @@ namespace Microsoft.ComponentDetection.Detectors.Tests; using System.Linq; using System.Threading.Tasks; using FluentAssertions; +using Microsoft.ComponentDetection.Common; using Microsoft.ComponentDetection.Contracts; using Microsoft.ComponentDetection.Contracts.TypedComponent; using Microsoft.ComponentDetection.Detectors.Pip; +using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -48,15 +50,24 @@ public class PythonCommandServiceTests other=2.1"; private readonly Mock commandLineInvokationService; + private readonly Mock> logger; + private readonly Mock> pathLogger; + private readonly IPathUtilityService pathUtilityService; - public PythonCommandServiceTests() => this.commandLineInvokationService = new Mock(); + public PythonCommandServiceTests() + { + this.commandLineInvokationService = new Mock(); + this.logger = new Mock>(); + this.pathLogger = new Mock>(); + this.pathUtilityService = new PathUtilityService(this.pathLogger.Object); + } [TestMethod] public async Task PythonCommandService_ReturnsTrueWhenPythonExistsAsync() { this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(true); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); (await service.PythonExistsAsync()).Should().BeTrue(); } @@ -66,7 +77,7 @@ public async Task PythonCommandService_ReturnsFalseWhenPythonExistsAsync() { this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(false); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); (await service.PythonExistsAsync()).Should().BeFalse(); } @@ -76,7 +87,7 @@ public async Task PythonCommandService_ReturnsTrueWhenPythonExistsForAPathAsync( { this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("test", It.IsAny>(), "--version")).ReturnsAsync(true); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); (await service.PythonExistsAsync("test")).Should().BeTrue(); } @@ -86,7 +97,7 @@ public async Task PythonCommandService_ReturnsFalseWhenPythonExistsForAPathAsync { this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("test", It.IsAny>(), "--version")).ReturnsAsync(false); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); (await service.PythonExistsAsync("test")).Should().BeFalse(); } @@ -95,13 +106,13 @@ public async Task PythonCommandService_ReturnsFalseWhenPythonExistsForAPathAsync public async Task PythonCommandService_ParsesEmptySetupPyOutputCorrectlyAsync() { var fakePath = @"c:\the\fake\path.py"; - var fakePathAsPassedToPython = fakePath.Replace("\\", "/"); + var fakePathAsPassedToPython = this.pathUtilityService.NormalizePath(fakePath); this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(true); - this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync("python", It.IsAny>(), It.Is(c => c.Contains(fakePathAsPassedToPython)))) + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync("python", It.IsAny>(), It.IsAny(), It.Is(c => c.Contains(fakePathAsPassedToPython)))) .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = "[]", StdErr = string.Empty }); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); var result = await service.ParseFileAsync(fakePath); @@ -112,13 +123,13 @@ public async Task PythonCommandService_ParsesEmptySetupPyOutputCorrectlyAsync() public async Task PythonCommandService_ParsesEmptySetupPyOutputCorrectly_Python27Async() { var fakePath = @"c:\the\fake\path.py"; - var fakePathAsPassedToPython = fakePath.Replace("\\", "/"); + var fakePathAsPassedToPython = this.pathUtilityService.NormalizePath(fakePath); this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(true); - this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync("python", It.IsAny>(), It.Is(c => c.Contains(fakePathAsPassedToPython)))) + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync("python", It.IsAny>(), It.IsAny(), It.Is(c => c.Contains(fakePathAsPassedToPython)))) .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = "None", StdErr = string.Empty }); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); var result = await service.ParseFileAsync(fakePath); @@ -129,13 +140,13 @@ public async Task PythonCommandService_ParsesEmptySetupPyOutputCorrectly_Python2 public async Task PythonCommandService_ParsesSetupPyOutputCorrectly_Python27NonePkgAsync() { var fakePath = @"c:\the\fake\path.py"; - var fakePathAsPassedToPython = fakePath.Replace("\\", "/"); + var fakePathAsPassedToPython = this.pathUtilityService.NormalizePath(fakePath); this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(true); - this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync("python", It.IsAny>(), It.Is(c => c.Contains(fakePathAsPassedToPython)))) + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync("python", It.IsAny>(), It.IsAny(), It.Is(c => c.Contains(fakePathAsPassedToPython)))) .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = "['None']", StdErr = string.Empty }); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); var result = await service.ParseFileAsync(fakePath); @@ -147,13 +158,13 @@ public async Task PythonCommandService_ParsesSetupPyOutputCorrectly_Python27None public async Task PythonCommandService_ParsesRegularSetupPyOutputCorrectlyAsync() { var fakePath = @"c:\the\fake\path.py"; - var fakePathAsPassedToPython = fakePath.Replace("\\", "/"); + var fakePathAsPassedToPython = this.pathUtilityService.NormalizePath(fakePath); this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(true); - this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync("python", It.IsAny>(), It.Is(c => c.Contains(fakePathAsPassedToPython)))) + this.commandLineInvokationService.Setup(x => x.ExecuteCommandAsync("python", It.IsAny>(), It.IsAny(), It.Is(c => c.Contains(fakePathAsPassedToPython)))) .ReturnsAsync(new CommandLineExecutionResult { ExitCode = 0, StdOut = "['knack==0.4.1', 'setuptools>=1.0,!=1.1', 'vsts-cli-common==0.1.3', 'vsts-cli-admin==0.1.3', 'vsts-cli-build==0.1.3', 'vsts-cli-code==0.1.3', 'vsts-cli-team==0.1.3', 'vsts-cli-package==0.1.3', 'vsts-cli-work==0.1.3']", StdErr = string.Empty }); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); var result = await service.ParseFileAsync(fakePath); var expected = new string[] { "knack==0.4.1", "setuptools>=1.0,!=1.1", "vsts-cli-common==0.1.3", "vsts-cli-admin==0.1.3", "vsts-cli-build==0.1.3", "vsts-cli-code==0.1.3", "vsts-cli-team==0.1.3", "vsts-cli-package==0.1.3", "vsts-cli-work==0.1.3" }.Select(dep => (dep, null)).ToArray(); @@ -172,7 +183,7 @@ public async Task PythonCommandService_ParsesRequirementsTxtCorrectlyAsync() var testPath = Path.Join(Directory.GetCurrentDirectory(), string.Join(Guid.NewGuid().ToString(), ".txt")); this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(true); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); try { @@ -210,7 +221,7 @@ public async Task ParseFile_RequirementTxtHasComment_CommentAreIgnoredAsync() var testPath = Path.Join(Directory.GetCurrentDirectory(), string.Join(Guid.NewGuid().ToString(), ".txt")); this.commandLineInvokationService.Setup(x => x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(true); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); try { @@ -392,7 +403,7 @@ private async Task SetupAndParseReqsTxtAsync(string fileToParse, Action x.CanCommandBeLocatedAsync("python", It.IsAny>(), "--version")).ReturnsAsync(true); - var service = new PythonCommandService(this.commandLineInvokationService.Object); + var service = new PythonCommandService(this.commandLineInvokationService.Object, this.pathUtilityService, this.logger.Object); using (var writer = File.CreateText(testPath)) { diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/Utilities/ComponentRecorderTestUtilities.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/Utilities/ComponentRecorderTestUtilities.cs index 7ea28f197..bcd189b9c 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/Utilities/ComponentRecorderTestUtilities.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/Utilities/ComponentRecorderTestUtilities.cs @@ -1,10 +1,12 @@ -namespace Microsoft.ComponentDetection.Detectors.Tests.Utilities; +namespace Microsoft.ComponentDetection.Detectors.Tests.Utilities; using System; using System.Collections.Generic; using System.Linq; +using FluentAssertions; using Microsoft.ComponentDetection.Contracts; using Microsoft.ComponentDetection.Contracts.TypedComponent; +using Newtonsoft.Json; public static class ComponentRecorderTestUtilities { @@ -134,6 +136,41 @@ private static ComponentOrientedGrouping TupleToObject(IEnumerable<(string Locat .ToList(); } + public static void CheckGraphStructure(IDependencyGraph graph, Dictionary graphComponentsWithDeps) + { + var graphComponents = graph.GetComponents().ToArray(); + graphComponents.Should().HaveCount( + graphComponentsWithDeps.Keys.Count, + $"Expected {graphComponentsWithDeps.Keys.Count} component to be recorded but got {graphComponents.Length} instead!"); + + foreach (var componentId in graphComponentsWithDeps.Keys) + { + graphComponents.Should().Contain( + componentId, $"Component `{componentId}` not recorded!"); + + var recordedDeps = graph.GetDependenciesForComponent(componentId).ToArray(); + var expectedDeps = graphComponentsWithDeps[componentId]; + + recordedDeps.Should().HaveCount( + expectedDeps.Length, + $"Count missmatch of expected dependencies ({JsonConvert.SerializeObject(expectedDeps)}) and recorded dependencies ({JsonConvert.SerializeObject(recordedDeps)}) for `{componentId}`!"); + + foreach (var expectedDep in expectedDeps) + { + recordedDeps.Should().Contain( + expectedDep, $"Expected `{expectedDep}` in the list of dependencies for `{componentId}` but only recorded: {JsonConvert.SerializeObject(recordedDeps)}"); + } + } + } + + public static void CheckChild(IComponentRecorder recorder, string childId, string[] parentIds) + where T : TypedComponent + { + recorder.AssertAllExplicitlyReferencedComponents( + childId, + parentIds.Select(parentId => new Func(x => x.Id == parentId)).ToArray()); + } + public class ComponentOrientedGrouping { public IEnumerable<(string ManifestFile, IDependencyGraph Graph)> FoundInGraphs { get; set; }