mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
Merge branch 'main' into editor-3830
This commit is contained in:
commit
b1771895c5
94 changed files with 2306 additions and 2043 deletions
|
@ -10,3 +10,6 @@ PYTHONDONTWRITEBYTECODE = "1" # prevent junk files on Windows
|
|||
|
||||
[term]
|
||||
color = "always"
|
||||
|
||||
[target.'cfg(all(target_env = "msvc", target_os = "windows"))']
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
|
|
2
.version
2
.version
|
@ -1 +1 @@
|
|||
25.06b7
|
||||
25.08b1
|
||||
|
|
|
@ -233,6 +233,8 @@ Spiritual Father <https://github.com/spiritualfather>
|
|||
Emmanuel Ferdman <https://github.com/emmanuel-ferdman>
|
||||
Sunong2008 <https://github.com/Sunrongguo2008>
|
||||
Marvin Kopf <marvinkopf@outlook.com>
|
||||
Kevin Nakamura <grinkers@grinkers.net>
|
||||
|
||||
********************
|
||||
|
||||
The text of the 3 clause BSD license follows:
|
||||
|
|
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -94,6 +94,7 @@ dependencies = [
|
|||
"axum",
|
||||
"axum-client-ip",
|
||||
"axum-extra",
|
||||
"bitflags 2.9.1",
|
||||
"blake3",
|
||||
"bytes",
|
||||
"chrono",
|
||||
|
@ -3548,6 +3549,7 @@ dependencies = [
|
|||
"embed-resource",
|
||||
"libc",
|
||||
"libc-stdhandle",
|
||||
"serde_json",
|
||||
"widestring",
|
||||
"windows 0.61.3",
|
||||
]
|
||||
|
|
|
@ -60,6 +60,7 @@ async-trait = "0.1.88"
|
|||
axum = { version = "0.8.4", features = ["multipart", "macros"] }
|
||||
axum-client-ip = "1.1.3"
|
||||
axum-extra = { version = "0.10.1", features = ["typed-header"] }
|
||||
bitflags = "2.9.1"
|
||||
blake3 = "1.8.2"
|
||||
bytes = "1.10.1"
|
||||
camino = "1.1.10"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Anki
|
||||
# Anki®
|
||||
|
||||
[](https://buildkite.com/ankitects/anki-ci)
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use std::env;
|
||||
|
||||
use anyhow::Result;
|
||||
use ninja_gen::action::BuildAction;
|
||||
use ninja_gen::archives::Platform;
|
||||
|
@ -125,7 +123,14 @@ impl BuildAction for BuildWheel {
|
|||
}
|
||||
|
||||
fn files(&mut self, build: &mut impl FilesHandle) {
|
||||
if std::env::var("OFFLINE_BUILD").ok().as_deref() == Some("1") {
|
||||
let uv_path =
|
||||
std::env::var("UV_BINARY").expect("UV_BINARY must be set in OFFLINE_BUILD mode");
|
||||
build.add_inputs("uv", inputs![uv_path]);
|
||||
} else {
|
||||
build.add_inputs("uv", inputs![":uv_binary"]);
|
||||
}
|
||||
|
||||
build.add_inputs("", &self.deps);
|
||||
|
||||
// Set the project directory based on which package we're building
|
||||
|
@ -222,15 +227,19 @@ struct Sphinx {
|
|||
|
||||
impl BuildAction for Sphinx {
|
||||
fn command(&self) -> &str {
|
||||
if env::var("OFFLINE_BUILD").is_err() {
|
||||
"$uv sync --extra sphinx && $python python/sphinx/build.py"
|
||||
} else {
|
||||
if std::env::var("OFFLINE_BUILD").ok().as_deref() == Some("1") {
|
||||
"$python python/sphinx/build.py"
|
||||
} else {
|
||||
"$uv sync --extra sphinx && $python python/sphinx/build.py"
|
||||
}
|
||||
}
|
||||
|
||||
fn files(&mut self, build: &mut impl FilesHandle) {
|
||||
if env::var("OFFLINE_BUILD").is_err() {
|
||||
if std::env::var("OFFLINE_BUILD").ok().as_deref() == Some("1") {
|
||||
let uv_path =
|
||||
std::env::var("UV_BINARY").expect("UV_BINARY must be set in OFFLINE_BUILD mode");
|
||||
build.add_inputs("uv", inputs![uv_path]);
|
||||
} else {
|
||||
build.add_inputs("uv", inputs![":uv_binary"]);
|
||||
// Set environment variable to use the existing pyenv
|
||||
build.add_variable("pyenv_path", "$builddir/pyenv");
|
||||
|
|
|
@ -35,3 +35,7 @@ path = "src/bin/update_uv.rs"
|
|||
[[bin]]
|
||||
name = "update_protoc"
|
||||
path = "src/bin/update_protoc.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "update_node"
|
||||
path = "src/bin/update_node.rs"
|
||||
|
|
268
build/ninja_gen/src/bin/update_node.rs
Normal file
268
build/ninja_gen/src/bin/update_node.rs
Normal file
|
@ -0,0 +1,268 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use regex::Regex;
|
||||
use reqwest::blocking::Client;
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NodeRelease {
|
||||
version: String,
|
||||
files: Vec<NodeFile>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct NodeFile {
|
||||
filename: String,
|
||||
url: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let release_info = fetch_node_release_info()?;
|
||||
let new_text = generate_node_archive_function(&release_info)?;
|
||||
update_node_text(&new_text)?;
|
||||
println!("Node.js archive function updated successfully!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fetch_node_release_info() -> Result<NodeRelease, Box<dyn Error>> {
|
||||
let client = Client::new();
|
||||
|
||||
// Get the Node.js release info
|
||||
let response = client
|
||||
.get("https://nodejs.org/dist/index.json")
|
||||
.header("User-Agent", "anki-build-updater")
|
||||
.send()?;
|
||||
|
||||
let releases: Vec<Value> = response.json()?;
|
||||
|
||||
// Find the latest LTS release
|
||||
let latest = releases
|
||||
.iter()
|
||||
.find(|release| {
|
||||
// LTS releases have a non-false "lts" field
|
||||
release["lts"].as_str().is_some() && release["lts"] != false
|
||||
})
|
||||
.ok_or("No LTS releases found")?;
|
||||
|
||||
let version = latest["version"]
|
||||
.as_str()
|
||||
.ok_or("Version not found")?
|
||||
.to_string();
|
||||
|
||||
let files = latest["files"]
|
||||
.as_array()
|
||||
.ok_or("Files array not found")?
|
||||
.iter()
|
||||
.map(|f| f.as_str().unwrap_or(""))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let lts_name = latest["lts"].as_str().unwrap_or("unknown");
|
||||
println!("Found Node.js LTS version: {version} ({lts_name})");
|
||||
|
||||
// Map platforms to their expected file keys and full filenames
|
||||
let platform_mapping = vec![
|
||||
(
|
||||
"linux-x64",
|
||||
"linux-x64",
|
||||
format!("node-{version}-linux-x64.tar.xz"),
|
||||
),
|
||||
(
|
||||
"linux-arm64",
|
||||
"linux-arm64",
|
||||
format!("node-{version}-linux-arm64.tar.xz"),
|
||||
),
|
||||
(
|
||||
"darwin-x64",
|
||||
"osx-x64-tar",
|
||||
format!("node-{version}-darwin-x64.tar.xz"),
|
||||
),
|
||||
(
|
||||
"darwin-arm64",
|
||||
"osx-arm64-tar",
|
||||
format!("node-{version}-darwin-arm64.tar.xz"),
|
||||
),
|
||||
(
|
||||
"win-x64",
|
||||
"win-x64-zip",
|
||||
format!("node-{version}-win-x64.zip"),
|
||||
),
|
||||
(
|
||||
"win-arm64",
|
||||
"win-arm64-zip",
|
||||
format!("node-{version}-win-arm64.zip"),
|
||||
),
|
||||
];
|
||||
|
||||
let mut node_files = Vec::new();
|
||||
|
||||
for (platform, file_key, filename) in platform_mapping {
|
||||
// Check if this file exists in the release
|
||||
if files.contains(&file_key) {
|
||||
let url = format!("https://nodejs.org/dist/{version}/{filename}");
|
||||
node_files.push(NodeFile {
|
||||
filename: filename.clone(),
|
||||
url,
|
||||
});
|
||||
println!("Found file for {platform}: {filename} (key: {file_key})");
|
||||
} else {
|
||||
return Err(
|
||||
format!("File not found for {platform} (key: {file_key}): {filename}").into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(NodeRelease {
|
||||
version,
|
||||
files: node_files,
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_node_archive_function(release: &NodeRelease) -> Result<String, Box<dyn Error>> {
|
||||
let client = Client::new();
|
||||
|
||||
// Fetch the SHASUMS256.txt file once
|
||||
println!("Fetching SHA256 checksums...");
|
||||
let shasums_url = format!("https://nodejs.org/dist/{}/SHASUMS256.txt", release.version);
|
||||
let shasums_response = client
|
||||
.get(&shasums_url)
|
||||
.header("User-Agent", "anki-build-updater")
|
||||
.send()?;
|
||||
let shasums_text = shasums_response.text()?;
|
||||
|
||||
// Create a mapping from filename patterns to platform names - using the exact
|
||||
// patterns we stored in files
|
||||
let platform_mapping = vec![
|
||||
("linux-x64.tar.xz", "LinuxX64"),
|
||||
("linux-arm64.tar.xz", "LinuxArm"),
|
||||
("darwin-x64.tar.xz", "MacX64"),
|
||||
("darwin-arm64.tar.xz", "MacArm"),
|
||||
("win-x64.zip", "WindowsX64"),
|
||||
("win-arm64.zip", "WindowsArm"),
|
||||
];
|
||||
|
||||
let mut platform_blocks = Vec::new();
|
||||
|
||||
for (file_pattern, platform_name) in platform_mapping {
|
||||
// Find the file that ends with this pattern
|
||||
if let Some(file) = release
|
||||
.files
|
||||
.iter()
|
||||
.find(|f| f.filename.ends_with(file_pattern))
|
||||
{
|
||||
// Find the SHA256 for this file
|
||||
let sha256 = shasums_text
|
||||
.lines()
|
||||
.find(|line| line.contains(&file.filename))
|
||||
.and_then(|line| line.split_whitespace().next())
|
||||
.ok_or_else(|| format!("SHA256 not found for {}", file.filename))?;
|
||||
|
||||
println!(
|
||||
"Found SHA256 for {}: {} => {}",
|
||||
platform_name, file.filename, sha256
|
||||
);
|
||||
|
||||
let block = format!(
|
||||
" Platform::{} => OnlineArchive {{\n url: \"{}\",\n sha256: \"{}\",\n }},",
|
||||
platform_name, file.url, sha256
|
||||
);
|
||||
platform_blocks.push(block);
|
||||
} else {
|
||||
return Err(format!(
|
||||
"File not found for platform {platform_name}: no file ending with {file_pattern}"
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
let function = format!(
|
||||
"pub fn node_archive(platform: Platform) -> OnlineArchive {{\n match platform {{\n{}\n }}\n}}",
|
||||
platform_blocks.join("\n")
|
||||
);
|
||||
|
||||
Ok(function)
|
||||
}
|
||||
|
||||
fn update_node_text(new_function: &str) -> Result<(), Box<dyn Error>> {
|
||||
let node_rs_content = read_node_rs()?;
|
||||
|
||||
// Regex to match the entire node_archive function with proper multiline
|
||||
// matching
|
||||
let re = Regex::new(
|
||||
r"(?s)pub fn node_archive\(platform: Platform\) -> OnlineArchive \{.*?\n\s*\}\s*\n\s*\}",
|
||||
)?;
|
||||
|
||||
let updated_content = re.replace(&node_rs_content, new_function);
|
||||
|
||||
write_node_rs(&updated_content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_node_rs() -> Result<String, Box<dyn Error>> {
|
||||
// Use CARGO_MANIFEST_DIR to get the crate root, then find src/node.rs
|
||||
let manifest_dir =
|
||||
std::env::var("CARGO_MANIFEST_DIR").map_err(|_| "CARGO_MANIFEST_DIR not set")?;
|
||||
let path = Path::new(&manifest_dir).join("src").join("node.rs");
|
||||
Ok(fs::read_to_string(path)?)
|
||||
}
|
||||
|
||||
fn write_node_rs(content: &str) -> Result<(), Box<dyn Error>> {
|
||||
// Use CARGO_MANIFEST_DIR to get the crate root, then find src/node.rs
|
||||
let manifest_dir =
|
||||
std::env::var("CARGO_MANIFEST_DIR").map_err(|_| "CARGO_MANIFEST_DIR not set")?;
|
||||
let path = Path::new(&manifest_dir).join("src").join("node.rs");
|
||||
fs::write(path, content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_regex_replacement() {
|
||||
let sample_content = r#"Some other code
|
||||
pub fn node_archive(platform: Platform) -> OnlineArchive {
|
||||
match platform {
|
||||
Platform::LinuxX64 => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v20.11.0/node-v20.11.0-linux-x64.tar.xz",
|
||||
sha256: "old_hash",
|
||||
},
|
||||
Platform::MacX64 => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v20.11.0/node-v20.11.0-darwin-x64.tar.xz",
|
||||
sha256: "old_hash",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
More code here"#;
|
||||
|
||||
let new_function = r#"pub fn node_archive(platform: Platform) -> OnlineArchive {
|
||||
match platform {
|
||||
Platform::LinuxX64 => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v21.0.0/node-v21.0.0-linux-x64.tar.xz",
|
||||
sha256: "new_hash",
|
||||
},
|
||||
Platform::MacX64 => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v21.0.0/node-v21.0.0-darwin-x64.tar.xz",
|
||||
sha256: "new_hash",
|
||||
},
|
||||
}
|
||||
}"#;
|
||||
|
||||
let re = Regex::new(
|
||||
r"(?s)pub fn node_archive\(platform: Platform\) -> OnlineArchive \{.*?\n\s*\}\s*\n\s*\}"
|
||||
).unwrap();
|
||||
|
||||
let result = re.replace(sample_content, new_function);
|
||||
assert!(result.contains("v21.0.0"));
|
||||
assert!(result.contains("new_hash"));
|
||||
assert!(!result.contains("old_hash"));
|
||||
assert!(result.contains("Some other code"));
|
||||
assert!(result.contains("More code here"));
|
||||
}
|
||||
}
|
|
@ -19,28 +19,28 @@ use crate::input::BuildInput;
|
|||
pub fn node_archive(platform: Platform) -> OnlineArchive {
|
||||
match platform {
|
||||
Platform::LinuxX64 => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v20.11.0/node-v20.11.0-linux-x64.tar.xz",
|
||||
sha256: "822780369d0ea309e7d218e41debbd1a03f8cdf354ebf8a4420e89f39cc2e612",
|
||||
url: "https://nodejs.org/dist/v22.17.0/node-v22.17.0-linux-x64.tar.xz",
|
||||
sha256: "325c0f1261e0c61bcae369a1274028e9cfb7ab7949c05512c5b1e630f7e80e12",
|
||||
},
|
||||
Platform::LinuxArm => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v20.11.0/node-v20.11.0-linux-arm64.tar.xz",
|
||||
sha256: "f6df68c6793244071f69023a9b43a0cf0b13d65cbe86d55925c28e4134d9aafb",
|
||||
url: "https://nodejs.org/dist/v22.17.0/node-v22.17.0-linux-arm64.tar.xz",
|
||||
sha256: "140aee84be6774f5fb3f404be72adbe8420b523f824de82daeb5ab218dab7b18",
|
||||
},
|
||||
Platform::MacX64 => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v20.11.0/node-v20.11.0-darwin-x64.tar.xz",
|
||||
sha256: "d4b4ab81ebf1f7aab09714f834992f27270ad0079600da00c8110f8950ca6c5a",
|
||||
url: "https://nodejs.org/dist/v22.17.0/node-v22.17.0-darwin-x64.tar.xz",
|
||||
sha256: "f79de1f64df4ac68493a344bb5ab7d289d0275271e87b543d1278392c9de778a",
|
||||
},
|
||||
Platform::MacArm => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v20.11.0/node-v20.11.0-darwin-arm64.tar.xz",
|
||||
sha256: "f18a7438723d48417f5e9be211a2f3c0520ffbf8e02703469e5153137ca0f328",
|
||||
url: "https://nodejs.org/dist/v22.17.0/node-v22.17.0-darwin-arm64.tar.xz",
|
||||
sha256: "cc9cc294eaf782dd93c8c51f460da610cc35753c6a9947411731524d16e97914",
|
||||
},
|
||||
Platform::WindowsX64 => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v20.11.0/node-v20.11.0-win-x64.zip",
|
||||
sha256: "893115cd92ad27bf178802f15247115e93c0ef0c753b93dca96439240d64feb5",
|
||||
url: "https://nodejs.org/dist/v22.17.0/node-v22.17.0-win-x64.zip",
|
||||
sha256: "721ab118a3aac8584348b132767eadf51379e0616f0db802cc1e66d7f0d98f85",
|
||||
},
|
||||
Platform::WindowsArm => OnlineArchive {
|
||||
url: "https://nodejs.org/dist/v20.11.0/node-v20.11.0-win-arm64.zip",
|
||||
sha256: "89c1f7034dcd6ff5c17f2af61232a96162a1902f862078347dcf274a938b6142",
|
||||
url: "https://nodejs.org/dist/v22.17.0/node-v22.17.0-win-arm64.zip",
|
||||
sha256: "78355dc9ca117bb71d3f081e4b1b281855e2b134f3939bb0ca314f7567b0e621",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 4a65d6012ac022a35f5c80c80b2b665447b6a525
|
||||
Subproject commit a9216499ba1fb1538cfd740c698adaaa3410fd4b
|
|
@ -426,7 +426,7 @@ deck-config-desired-retention-tooltip =
|
|||
values will greatly increase your workload, and lower values can be demoralizing when you forget
|
||||
a lot of material.
|
||||
deck-config-desired-retention-tooltip2 =
|
||||
The workload values provided by the tooltip are a rough approximation. For a greater level of accuracy, use the simulator.
|
||||
The workload values provided by the info box are a rough approximation. For a greater level of accuracy, use the simulator.
|
||||
deck-config-historical-retention-tooltip =
|
||||
When some of your review history is missing, FSRS needs to fill in the gaps. By default, it will
|
||||
assume that when you did those old reviews, you remembered 90% of the material. If your old retention
|
||||
|
@ -514,6 +514,7 @@ deck-config-advanced-settings = Advanced Settings
|
|||
deck-config-smooth-graph = Smooth graph
|
||||
deck-config-suspend-leeches = Suspend leeches
|
||||
deck-config-save-options-to-preset = Save Changes to Preset
|
||||
deck-config-save-options-to-preset-confirm = Overwrite the options in your current preset with the options that are currently set in the simulator?
|
||||
# Radio button in the FSRS simulation diagram (Deck options -> FSRS) selecting
|
||||
# to show the total number of cards that can be recalled or retrieved on a
|
||||
# specific date.
|
||||
|
|
|
@ -48,6 +48,7 @@ importing-merge-notetypes-help =
|
|||
Warning: This will require a one-way sync, and may mark existing notes as modified.
|
||||
importing-mnemosyne-20-deck-db = Mnemosyne 2.0 Deck (*.db)
|
||||
importing-multicharacter-separators-are-not-supported-please = Multi-character separators are not supported. Please enter one character only.
|
||||
importing-new-deck-will-be-created = A new deck will be created: { $name }
|
||||
importing-notes-added-from-file = Notes added from file: { $val }
|
||||
importing-notes-found-in-file = Notes found in file: { $val }
|
||||
importing-notes-skipped-as-theyre-already-in = Notes skipped, as up-to-date copies are already in your collection: { $val }
|
||||
|
|
|
@ -99,9 +99,9 @@ statistics-counts-relearning-cards = Relearning
|
|||
statistics-counts-title = Card Counts
|
||||
statistics-counts-separate-suspended-buried-cards = Separate suspended/buried cards
|
||||
|
||||
## True Retention represents your actual retention rate from past reviews, in
|
||||
## comparison to the "desired retention" parameter of FSRS, which forecasts
|
||||
## future retention. True Retention is the percentage of all reviewed cards
|
||||
## Retention rate represents your actual retention rate from past reviews, in
|
||||
## comparison to the "desired retention" setting of FSRS, which forecasts
|
||||
## future retention. Retention rate is the percentage of all reviewed cards
|
||||
## that were marked as "Hard," "Good," or "Easy" within a specific time period.
|
||||
##
|
||||
## Most of these strings are used as column / row headings in a table.
|
||||
|
@ -112,9 +112,9 @@ statistics-counts-separate-suspended-buried-cards = Separate suspended/buried ca
|
|||
## N.B. Stats cards may be very small on mobile devices and when the Stats
|
||||
## window is certain sizes.
|
||||
|
||||
statistics-true-retention-title = True Retention
|
||||
statistics-true-retention-title = Retention rate
|
||||
statistics-true-retention-subtitle = Pass rate of cards with an interval ≥ 1 day.
|
||||
statistics-true-retention-tooltip = If you are using FSRS, your true retention is expected to be close to your desired retention. Please keep in mind that data for a single day is noisy, so it's better to look at monthly data.
|
||||
statistics-true-retention-tooltip = If you are using FSRS, your retention rate is expected to be close to your desired retention. Please keep in mind that data for a single day is noisy, so it's better to look at monthly data.
|
||||
statistics-true-retention-range = Range
|
||||
statistics-true-retention-pass = Pass
|
||||
statistics-true-retention-fail = Fail
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f42461a6438cbe844150f543128d79a669bc4ef2
|
||||
Subproject commit a1134ab59d3d23468af2968741aa1f21d16ff308
|
21
package.json
21
package.json
|
@ -19,8 +19,8 @@
|
|||
"@poppanator/sveltekit-svg": "^5.0.0",
|
||||
"@sqltools/formatter": "^1.2.2",
|
||||
"@sveltejs/adapter-static": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.20.7",
|
||||
"@sveltejs/vite-plugin-svelte": "4.0.0",
|
||||
"@sveltejs/kit": "^2.22.2",
|
||||
"@sveltejs/vite-plugin-svelte": "5.1",
|
||||
"@types/bootstrap": "^5.0.12",
|
||||
"@types/codemirror": "^5.60.0",
|
||||
"@types/d3": "^7.0.0",
|
||||
|
@ -30,7 +30,7 @@
|
|||
"@types/jqueryui": "^1.12.13",
|
||||
"@types/lodash-es": "^4.17.4",
|
||||
"@types/marked": "^5.0.0",
|
||||
"@types/node": "^20",
|
||||
"@types/node": "^22",
|
||||
"@typescript-eslint/eslint-plugin": "^5.60.1",
|
||||
"@typescript-eslint/parser": "^5.60.1",
|
||||
"caniuse-lite": "^1.0.30001431",
|
||||
|
@ -48,16 +48,16 @@
|
|||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-svelte": "^3.3.2",
|
||||
"sass": "<1.77",
|
||||
"svelte": "^5.17.3",
|
||||
"svelte-check": "^3.4.4",
|
||||
"svelte-preprocess": "^5.0.4",
|
||||
"svelte": "^5.34.9",
|
||||
"svelte-check": "^4.2.2",
|
||||
"svelte-preprocess": "^6.0.3",
|
||||
"svelte-preprocess-esbuild": "^3.0.1",
|
||||
"svgo": "^3.2.0",
|
||||
"tslib": "^2.0.3",
|
||||
"tsx": "^3.12.0",
|
||||
"tsx": "^4.8.1",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "5.4.19",
|
||||
"vitest": "^2"
|
||||
"vite": "6",
|
||||
"vitest": "^3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^1.2.1",
|
||||
|
@ -82,7 +82,8 @@
|
|||
},
|
||||
"resolutions": {
|
||||
"canvas": "npm:empty-npm-package@1.0.0",
|
||||
"cookie": "0.7.0"
|
||||
"cookie": "0.7.0",
|
||||
"vite": "6"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults",
|
||||
|
|
|
@ -51,6 +51,7 @@ message Card {
|
|||
optional FsrsMemoryState memory_state = 20;
|
||||
optional float desired_retention = 21;
|
||||
optional float decay = 22;
|
||||
optional int64 last_review_time_secs = 23;
|
||||
string custom_data = 19;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ message ConfigKey {
|
|||
RENDER_LATEX = 25;
|
||||
LOAD_BALANCER_ENABLED = 26;
|
||||
FSRS_SHORT_TERM_WITH_STEPS_ENABLED = 27;
|
||||
FSRS_LEGACY_EVALUATE = 28;
|
||||
}
|
||||
enum String {
|
||||
SET_DUE_BROWSER = 0;
|
||||
|
|
|
@ -236,6 +236,7 @@ message DeckConfigsForUpdate {
|
|||
bool new_cards_ignore_review_limit = 7;
|
||||
bool fsrs = 8;
|
||||
bool fsrs_health_check = 11;
|
||||
bool fsrs_legacy_evaluate = 12;
|
||||
bool apply_all_parent_limits = 9;
|
||||
uint32 days_since_last_fsrs_optimize = 10;
|
||||
}
|
||||
|
|
|
@ -176,9 +176,12 @@ message CsvMetadata {
|
|||
// to determine the number of columns.
|
||||
repeated string column_labels = 5;
|
||||
oneof deck {
|
||||
// id of an existing deck
|
||||
int64 deck_id = 6;
|
||||
// One-based. 0 means n/a.
|
||||
uint32 deck_column = 7;
|
||||
// name of new deck to be created
|
||||
string deck_name = 17;
|
||||
}
|
||||
oneof notetype {
|
||||
// One notetype for all rows with given column mapping.
|
||||
|
|
|
@ -56,6 +56,8 @@ service SchedulerService {
|
|||
rpc SimulateFsrsReview(SimulateFsrsReviewRequest)
|
||||
returns (SimulateFsrsReviewResponse);
|
||||
rpc EvaluateParams(EvaluateParamsRequest) returns (EvaluateParamsResponse);
|
||||
rpc EvaluateParamsLegacy(EvaluateParamsLegacyRequest)
|
||||
returns (EvaluateParamsResponse);
|
||||
rpc ComputeMemoryState(cards.CardId) returns (ComputeMemoryStateResponse);
|
||||
// The number of days the calculated interval was fuzzed by on the previous
|
||||
// review (if any). Utilized by the FSRS add-on.
|
||||
|
@ -402,31 +404,6 @@ message SimulateFsrsReviewRequest {
|
|||
repeated float easy_days_percentages = 10;
|
||||
deck_config.DeckConfig.Config.ReviewCardOrder review_order = 11;
|
||||
optional uint32 suspend_after_lapse_count = 12;
|
||||
// For CMRR
|
||||
message CMRRTarget {
|
||||
message Memorized {
|
||||
float loss_aversion = 1;
|
||||
};
|
||||
|
||||
message Stability {};
|
||||
|
||||
message FutureMemorized {
|
||||
int32 days = 1;
|
||||
};
|
||||
|
||||
message AverageFutureMemorized {
|
||||
int32 days = 1;
|
||||
};
|
||||
|
||||
oneof kind {
|
||||
Memorized memorized = 1;
|
||||
Stability stability = 2;
|
||||
FutureMemorized future_memorized = 3;
|
||||
AverageFutureMemorized average_future_memorized = 4;
|
||||
};
|
||||
};
|
||||
|
||||
optional CMRRTarget target = 13;
|
||||
}
|
||||
|
||||
message SimulateFsrsReviewResponse {
|
||||
|
@ -467,6 +444,12 @@ message EvaluateParamsRequest {
|
|||
uint32 num_of_relearning_steps = 3;
|
||||
}
|
||||
|
||||
message EvaluateParamsLegacyRequest {
|
||||
repeated float params = 1;
|
||||
string search = 2;
|
||||
int64 ignore_revlogs_before_ms = 3;
|
||||
}
|
||||
|
||||
message EvaluateParamsResponse {
|
||||
float log_loss = 1;
|
||||
float rmse_bins = 2;
|
||||
|
|
|
@ -49,6 +49,7 @@ class Card(DeprecatedNamesMixin):
|
|||
memory_state: FSRSMemoryState | None
|
||||
desired_retention: float | None
|
||||
decay: float | None
|
||||
last_review_time: int | None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -103,6 +104,11 @@ class Card(DeprecatedNamesMixin):
|
|||
card.desired_retention if card.HasField("desired_retention") else None
|
||||
)
|
||||
self.decay = card.decay if card.HasField("decay") else None
|
||||
self.last_review_time = (
|
||||
card.last_review_time_secs
|
||||
if card.HasField("last_review_time_secs")
|
||||
else None
|
||||
)
|
||||
|
||||
def _to_backend_card(self) -> cards_pb2.Card:
|
||||
# mtime & usn are set by backend
|
||||
|
|
|
@ -73,6 +73,7 @@ langs = sorted(
|
|||
("ଓଡ଼ିଆ", "or_OR"),
|
||||
("Filipino", "tl"),
|
||||
("ئۇيغۇر", "ug"),
|
||||
("Oʻzbek", "uz_UZ"),
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -123,6 +124,7 @@ compatMap = {
|
|||
"th": "th_TH",
|
||||
"tr": "tr_TR",
|
||||
"uk": "uk_UA",
|
||||
"uz": "uz_UZ",
|
||||
"vi": "vi_VN",
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,8 @@ def show(mw: aqt.AnkiQt) -> QDialog:
|
|||
# WebView contents
|
||||
######################################################################
|
||||
abouttext = "<center><img src='/_anki/imgs/anki-logo-thin.png'></center>"
|
||||
abouttext += f"<p>{tr.about_anki_is_a_friendly_intelligent_spaced()}"
|
||||
lede = tr.about_anki_is_a_friendly_intelligent_spaced().replace("Anki", "Anki®")
|
||||
abouttext += f"<p>{lede}"
|
||||
abouttext += f"<p>{tr.about_anki_is_licensed_under_the_agpl3()}"
|
||||
abouttext += f"<p>{tr.about_version(val=version_with_build())}<br>"
|
||||
abouttext += ("Python %s Qt %s PyQt %s<br>") % (
|
||||
|
@ -223,6 +224,7 @@ def show(mw: aqt.AnkiQt) -> QDialog:
|
|||
"Mukunda Madhav Dey",
|
||||
"Adnane Taghi",
|
||||
"Anon_0000",
|
||||
"Bilolbek Normuminov",
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -23,25 +23,36 @@ from aqt.utils import openHelp, showWarning, supportText, tooltip, tr
|
|||
if TYPE_CHECKING:
|
||||
from aqt.main import AnkiQt
|
||||
|
||||
# so we can be non-modal/non-blocking, without Python deallocating the message
|
||||
# box ahead of time
|
||||
_mbox: QMessageBox | None = None
|
||||
|
||||
|
||||
def show_exception(*, parent: QWidget, exception: Exception) -> None:
|
||||
"Present a caught exception to the user using a pop-up."
|
||||
if isinstance(exception, Interrupted):
|
||||
# nothing to do
|
||||
return
|
||||
global _mbox
|
||||
error_lines = []
|
||||
help_page = HelpPage.TROUBLESHOOTING
|
||||
if isinstance(exception, BackendError):
|
||||
if exception.context:
|
||||
print(exception.context)
|
||||
error_lines.append(exception.context)
|
||||
if exception.backtrace:
|
||||
print(exception.backtrace)
|
||||
showWarning(str(exception), parent=parent, help=exception.help_page)
|
||||
error_lines.append(exception.backtrace)
|
||||
if exception.help_page is not None:
|
||||
help_page = exception.help_page
|
||||
else:
|
||||
# if the error is not originating from the backend, dump
|
||||
# a traceback to the console to aid in debugging
|
||||
traceback.print_exception(
|
||||
None, exception, exception.__traceback__, file=sys.stdout
|
||||
error_lines = traceback.format_exception(
|
||||
None, exception, exception.__traceback__
|
||||
)
|
||||
showWarning(str(exception), parent=parent)
|
||||
error_text = "\n".join(error_lines)
|
||||
print(error_lines)
|
||||
_mbox = _init_message_box(str(exception), error_text, help_page)
|
||||
_mbox.show()
|
||||
|
||||
|
||||
def is_chromium_cert_error(error: str) -> bool:
|
||||
|
@ -158,9 +169,39 @@ if not os.environ.get("DEBUG"):
|
|||
|
||||
sys.excepthook = excepthook
|
||||
|
||||
# so we can be non-modal/non-blocking, without Python deallocating the message
|
||||
# box ahead of time
|
||||
_mbox: QMessageBox | None = None
|
||||
|
||||
def _init_message_box(
|
||||
user_text: str, debug_text: str, help_page=HelpPage.TROUBLESHOOTING
|
||||
):
|
||||
global _mbox
|
||||
|
||||
_mbox = QMessageBox()
|
||||
_mbox.setWindowTitle("Anki")
|
||||
_mbox.setText(user_text)
|
||||
_mbox.setIcon(QMessageBox.Icon.Warning)
|
||||
_mbox.setTextFormat(Qt.TextFormat.PlainText)
|
||||
|
||||
def show_help():
|
||||
openHelp(help_page)
|
||||
|
||||
def copy_debug_info():
|
||||
QApplication.clipboard().setText(debug_text)
|
||||
tooltip(tr.errors_copied_to_clipboard(), parent=_mbox)
|
||||
|
||||
help = _mbox.addButton(QMessageBox.StandardButton.Help)
|
||||
if debug_text:
|
||||
debug_info = _mbox.addButton(
|
||||
tr.errors_copy_debug_info_button(), QMessageBox.ButtonRole.ActionRole
|
||||
)
|
||||
debug_info.disconnect()
|
||||
debug_info.clicked.connect(copy_debug_info)
|
||||
cancel = _mbox.addButton(QMessageBox.StandardButton.Cancel)
|
||||
cancel.setText(tr.actions_close())
|
||||
|
||||
help.disconnect()
|
||||
help.clicked.connect(show_help)
|
||||
|
||||
return _mbox
|
||||
|
||||
|
||||
class ErrorHandler(QObject):
|
||||
|
@ -252,33 +293,7 @@ class ErrorHandler(QObject):
|
|||
user_text += "\n\n" + self._addonText(error)
|
||||
debug_text += addon_debug_info()
|
||||
|
||||
def show_troubleshooting():
|
||||
openHelp(HelpPage.TROUBLESHOOTING)
|
||||
|
||||
def copy_debug_info():
|
||||
QApplication.clipboard().setText(debug_text)
|
||||
tooltip(tr.errors_copied_to_clipboard(), parent=_mbox)
|
||||
|
||||
global _mbox
|
||||
_mbox = QMessageBox()
|
||||
_mbox.setWindowTitle("Anki")
|
||||
_mbox.setText(user_text)
|
||||
_mbox.setIcon(QMessageBox.Icon.Warning)
|
||||
_mbox.setTextFormat(Qt.TextFormat.PlainText)
|
||||
|
||||
troubleshooting = _mbox.addButton(
|
||||
tr.errors_troubleshooting_button(), QMessageBox.ButtonRole.ActionRole
|
||||
)
|
||||
debug_info = _mbox.addButton(
|
||||
tr.errors_copy_debug_info_button(), QMessageBox.ButtonRole.ActionRole
|
||||
)
|
||||
cancel = _mbox.addButton(QMessageBox.StandardButton.Cancel)
|
||||
cancel.setText(tr.actions_close())
|
||||
|
||||
troubleshooting.disconnect()
|
||||
troubleshooting.clicked.connect(show_troubleshooting)
|
||||
debug_info.disconnect()
|
||||
debug_info.clicked.connect(copy_debug_info)
|
||||
_mbox = _init_message_box(user_text, debug_text)
|
||||
|
||||
if self.fatal_error_encountered:
|
||||
_mbox.exec()
|
||||
|
|
|
@ -1309,7 +1309,7 @@ title="{}" {}>{}</button>""".format(
|
|||
if not askUser(tr.qt_misc_open_anki_launcher()):
|
||||
return
|
||||
|
||||
from aqt.update import update_and_restart
|
||||
from aqt.package import update_and_restart
|
||||
|
||||
update_and_restart()
|
||||
|
||||
|
@ -1394,7 +1394,7 @@ title="{}" {}>{}</button>""".format(
|
|||
##########################################################################
|
||||
|
||||
def setupMenus(self) -> None:
|
||||
from aqt.update import have_launcher
|
||||
from aqt.package import launcher_executable
|
||||
|
||||
m = self.form
|
||||
|
||||
|
@ -1426,7 +1426,7 @@ title="{}" {}>{}</button>""".format(
|
|||
qconnect(m.actionEmptyCards.triggered, self.onEmptyCards)
|
||||
qconnect(m.actionNoteTypes.triggered, self.onNoteTypes)
|
||||
qconnect(m.action_upgrade_downgrade.triggered, self.on_upgrade_downgrade)
|
||||
if not have_launcher():
|
||||
if not launcher_executable():
|
||||
m.action_upgrade_downgrade.setVisible(False)
|
||||
qconnect(m.actionPreferences.triggered, self.onPrefs)
|
||||
|
||||
|
|
|
@ -891,7 +891,7 @@ exposed_backend_list = [
|
|||
"compute_fsrs_params",
|
||||
"compute_optimal_retention",
|
||||
"set_wants_abort",
|
||||
"evaluate_params",
|
||||
"evaluate_params_legacy",
|
||||
"get_optimal_retention_parameters",
|
||||
"simulate_fsrs_review",
|
||||
# DeckConfigService
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from anki.utils import is_mac
|
||||
from anki.utils import is_mac, is_win
|
||||
|
||||
|
||||
# ruff: noqa: F401
|
||||
|
@ -65,3 +68,105 @@ def first_run_setup() -> None:
|
|||
# Wait for both commands to complete
|
||||
for proc in processes:
|
||||
proc.wait()
|
||||
|
||||
|
||||
def uv_binary() -> str | None:
|
||||
"""Return the path to the uv binary."""
|
||||
return os.environ.get("ANKI_LAUNCHER_UV")
|
||||
|
||||
|
||||
def launcher_root() -> str | None:
|
||||
"""Return the path to the launcher root directory (AnkiProgramFiles)."""
|
||||
return os.environ.get("UV_PROJECT")
|
||||
|
||||
|
||||
def venv_binary(cmd: str) -> str | None:
|
||||
"""Return the path to a binary in the launcher's venv."""
|
||||
root = launcher_root()
|
||||
if not root:
|
||||
return None
|
||||
|
||||
root_path = Path(root)
|
||||
if is_win:
|
||||
binary_path = root_path / ".venv" / "Scripts" / cmd
|
||||
else:
|
||||
binary_path = root_path / ".venv" / "bin" / cmd
|
||||
|
||||
return str(binary_path)
|
||||
|
||||
|
||||
def add_python_requirements(reqs: list[str]) -> tuple[bool, str]:
|
||||
"""Add Python requirements to the launcher venv using uv add.
|
||||
|
||||
Returns (success, output)"""
|
||||
|
||||
binary = uv_binary()
|
||||
if not binary:
|
||||
return (False, "Not in packaged build.")
|
||||
|
||||
uv_cmd = [binary, "add"] + reqs
|
||||
result = subprocess.run(uv_cmd, capture_output=True, text=True, check=False)
|
||||
|
||||
if result.returncode == 0:
|
||||
root = launcher_root()
|
||||
if root:
|
||||
sync_marker = Path(root) / ".sync_complete"
|
||||
sync_marker.touch()
|
||||
|
||||
return (True, result.stdout)
|
||||
else:
|
||||
return (False, result.stderr)
|
||||
|
||||
|
||||
def launcher_executable() -> str | None:
|
||||
"""Return the path to the Anki launcher executable."""
|
||||
return os.getenv("ANKI_LAUNCHER")
|
||||
|
||||
|
||||
def trigger_launcher_run() -> None:
|
||||
"""Bump the mtime on pyproject.toml in the local data directory to trigger an update on next run."""
|
||||
try:
|
||||
root = launcher_root()
|
||||
if not root:
|
||||
return
|
||||
|
||||
pyproject_path = Path(root) / "pyproject.toml"
|
||||
|
||||
if pyproject_path.exists():
|
||||
# Touch the file to update its mtime
|
||||
pyproject_path.touch()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def update_and_restart() -> None:
|
||||
"""Update and restart Anki using the launcher."""
|
||||
from aqt import mw
|
||||
|
||||
launcher = launcher_executable()
|
||||
assert launcher
|
||||
|
||||
trigger_launcher_run()
|
||||
|
||||
with contextlib.suppress(ResourceWarning):
|
||||
env = os.environ.copy()
|
||||
# fixes a bug where launcher fails to appear if opening it
|
||||
# straight after updating
|
||||
if "GNOME_TERMINAL_SCREEN" in env:
|
||||
del env["GNOME_TERMINAL_SCREEN"]
|
||||
creationflags = 0
|
||||
if sys.platform == "win32":
|
||||
creationflags = (
|
||||
subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS
|
||||
)
|
||||
subprocess.Popen(
|
||||
[launcher],
|
||||
start_new_session=True,
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
env=env,
|
||||
creationflags=creationflags,
|
||||
)
|
||||
|
||||
mw.app.quit()
|
||||
|
|
|
@ -3,16 +3,17 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import aqt
|
||||
from anki.buildinfo import buildhash
|
||||
from anki.collection import CheckForUpdateResponse, Collection
|
||||
from anki.utils import dev_mode, int_time, int_version, is_mac, is_win, plat_desc
|
||||
from anki.utils import dev_mode, int_time, int_version, plat_desc
|
||||
from aqt.operations import QueryOp
|
||||
from aqt.package import (
|
||||
launcher_executable as _launcher_executable,
|
||||
)
|
||||
from aqt.package import (
|
||||
update_and_restart as _update_and_restart,
|
||||
)
|
||||
from aqt.qt import *
|
||||
from aqt.utils import openLink, show_warning, showText, tr
|
||||
|
||||
|
@ -84,67 +85,7 @@ def prompt_to_update(mw: aqt.AnkiQt, ver: str) -> None:
|
|||
# ignore this update
|
||||
mw.pm.meta["suppressUpdate"] = ver
|
||||
elif ret == QMessageBox.StandardButton.Yes:
|
||||
if have_launcher():
|
||||
update_and_restart()
|
||||
if _launcher_executable():
|
||||
_update_and_restart()
|
||||
else:
|
||||
openLink(aqt.appWebsiteDownloadSection)
|
||||
|
||||
|
||||
def _anki_launcher_path() -> str | None:
|
||||
return os.getenv("ANKI_LAUNCHER")
|
||||
|
||||
|
||||
def have_launcher() -> bool:
|
||||
return _anki_launcher_path() is not None
|
||||
|
||||
|
||||
def update_and_restart() -> None:
|
||||
from aqt import mw
|
||||
|
||||
launcher = _anki_launcher_path()
|
||||
assert launcher
|
||||
|
||||
_trigger_launcher_run()
|
||||
|
||||
with contextlib.suppress(ResourceWarning):
|
||||
env = os.environ.copy()
|
||||
creationflags = 0
|
||||
if sys.platform == "win32":
|
||||
creationflags = (
|
||||
subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS
|
||||
)
|
||||
subprocess.Popen(
|
||||
[launcher],
|
||||
start_new_session=True,
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
env=env,
|
||||
creationflags=creationflags,
|
||||
)
|
||||
|
||||
mw.app.quit()
|
||||
|
||||
|
||||
def _trigger_launcher_run() -> None:
|
||||
"""Bump the mtime on pyproject.toml in the local data directory to trigger an update on next run."""
|
||||
try:
|
||||
# Get the local data directory equivalent to Rust's dirs::data_local_dir()
|
||||
if is_win:
|
||||
from .winpaths import get_local_appdata
|
||||
|
||||
data_dir = Path(get_local_appdata())
|
||||
elif is_mac:
|
||||
data_dir = Path.home() / "Library" / "Application Support"
|
||||
else: # Linux
|
||||
data_dir = Path(
|
||||
os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")
|
||||
)
|
||||
|
||||
pyproject_path = data_dir / "AnkiProgramFiles" / "pyproject.toml"
|
||||
|
||||
if pyproject_path.exists():
|
||||
# Touch the file to update its mtime
|
||||
pyproject_path.touch()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
|
|
@ -67,16 +67,12 @@ class CustomBuildHook(BuildHookInterface):
|
|||
|
||||
def _should_exclude(self, path: Path) -> bool:
|
||||
"""Check if a file should be excluded from the wheel."""
|
||||
path_str = str(path)
|
||||
|
||||
# Exclude __pycache__
|
||||
if "/__pycache__/" in path_str:
|
||||
if "/__pycache__/" in str(path):
|
||||
return True
|
||||
|
||||
if path.suffix in [".ui", ".scss", ".map", ".ts"]:
|
||||
return True
|
||||
if path.name.startswith("tsconfig"):
|
||||
return True
|
||||
if "/aqt/data" in path_str:
|
||||
return True
|
||||
return False
|
||||
|
|
|
@ -13,6 +13,10 @@ anki_process.workspace = true
|
|||
anyhow.workspace = true
|
||||
camino.workspace = true
|
||||
dirs.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
|
||||
libc.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows.workspace = true
|
||||
|
|
|
@ -8,29 +8,88 @@ import os
|
|||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import aqt.sound
|
||||
from anki.utils import pointVersion
|
||||
from aqt import mw
|
||||
from aqt.qt import QAction
|
||||
from aqt.utils import askUser, is_mac, is_win, showInfo
|
||||
|
||||
|
||||
def _anki_launcher_path() -> str | None:
|
||||
def launcher_executable() -> str | None:
|
||||
"""Return the path to the Anki launcher executable."""
|
||||
return os.getenv("ANKI_LAUNCHER")
|
||||
|
||||
|
||||
def have_launcher() -> bool:
|
||||
return _anki_launcher_path() is not None
|
||||
def uv_binary() -> str | None:
|
||||
"""Return the path to the uv binary."""
|
||||
return os.environ.get("ANKI_LAUNCHER_UV")
|
||||
|
||||
|
||||
def launcher_root() -> str | None:
|
||||
"""Return the path to the launcher root directory (AnkiProgramFiles)."""
|
||||
return os.environ.get("UV_PROJECT")
|
||||
|
||||
|
||||
def venv_binary(cmd: str) -> str | None:
|
||||
"""Return the path to a binary in the launcher's venv."""
|
||||
root = launcher_root()
|
||||
if not root:
|
||||
return None
|
||||
|
||||
root_path = Path(root)
|
||||
if is_win:
|
||||
binary_path = root_path / ".venv" / "Scripts" / cmd
|
||||
else:
|
||||
binary_path = root_path / ".venv" / "bin" / cmd
|
||||
|
||||
return str(binary_path)
|
||||
|
||||
|
||||
def add_python_requirements(reqs: list[str]) -> tuple[bool, str]:
|
||||
"""Add Python requirements to the launcher venv using uv add.
|
||||
|
||||
Returns (success, output)"""
|
||||
|
||||
binary = uv_binary()
|
||||
if not binary:
|
||||
return (False, "Not in packaged build.")
|
||||
|
||||
uv_cmd = [binary, "add"] + reqs
|
||||
result = subprocess.run(uv_cmd, capture_output=True, text=True, check=False)
|
||||
|
||||
if result.returncode == 0:
|
||||
root = launcher_root()
|
||||
if root:
|
||||
sync_marker = Path(root) / ".sync_complete"
|
||||
sync_marker.touch()
|
||||
return (True, result.stdout)
|
||||
else:
|
||||
return (False, result.stderr)
|
||||
|
||||
|
||||
def trigger_launcher_run() -> None:
|
||||
"""Bump the mtime on pyproject.toml in the local data directory to trigger an update on next run."""
|
||||
try:
|
||||
root = launcher_root()
|
||||
if not root:
|
||||
return
|
||||
|
||||
pyproject_path = Path(root) / "pyproject.toml"
|
||||
|
||||
if pyproject_path.exists():
|
||||
# Touch the file to update its mtime
|
||||
pyproject_path.touch()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def update_and_restart() -> None:
|
||||
from aqt import mw
|
||||
|
||||
launcher = _anki_launcher_path()
|
||||
"""Update and restart Anki using the launcher."""
|
||||
launcher = launcher_executable()
|
||||
assert launcher
|
||||
|
||||
_trigger_launcher_run()
|
||||
trigger_launcher_run()
|
||||
|
||||
with contextlib.suppress(ResourceWarning):
|
||||
env = os.environ.copy()
|
||||
|
@ -52,30 +111,6 @@ def update_and_restart() -> None:
|
|||
mw.app.quit()
|
||||
|
||||
|
||||
def _trigger_launcher_run() -> None:
|
||||
"""Bump the mtime on pyproject.toml in the local data directory to trigger an update on next run."""
|
||||
try:
|
||||
# Get the local data directory equivalent to Rust's dirs::data_local_dir()
|
||||
if is_win:
|
||||
from aqt.winpaths import get_local_appdata
|
||||
|
||||
data_dir = Path(get_local_appdata())
|
||||
elif is_mac:
|
||||
data_dir = Path.home() / "Library" / "Application Support"
|
||||
else: # Linux
|
||||
data_dir = Path(
|
||||
os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")
|
||||
)
|
||||
|
||||
pyproject_path = data_dir / "AnkiProgramFiles" / "pyproject.toml"
|
||||
|
||||
if pyproject_path.exists():
|
||||
# Touch the file to update its mtime
|
||||
pyproject_path.touch()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def confirm_then_upgrade():
|
||||
if not askUser("Change to a different Anki version?"):
|
||||
return
|
||||
|
@ -116,10 +151,18 @@ def _packagedCmd(cmd: list[str]) -> tuple[Any, dict[str, str]]:
|
|||
return cmd, env
|
||||
|
||||
|
||||
def on_addon_config():
|
||||
showInfo(
|
||||
"This add-on is automatically added when installing older Anki versions, so that they work with the launcher. You can remove it if you wish."
|
||||
)
|
||||
|
||||
|
||||
def setup():
|
||||
mw.addonManager.setConfigAction(__name__, on_addon_config)
|
||||
|
||||
if pointVersion() >= 250600:
|
||||
return
|
||||
if not have_launcher():
|
||||
if not launcher_executable():
|
||||
return
|
||||
|
||||
# Add action to tools menu
|
||||
|
@ -129,7 +172,21 @@ def setup():
|
|||
|
||||
# Monkey-patch audio tools to use anki-audio
|
||||
if is_win or is_mac:
|
||||
import aqt
|
||||
import aqt.sound
|
||||
|
||||
aqt.sound._packagedCmd = _packagedCmd
|
||||
|
||||
# Inject launcher functions into launcher module
|
||||
import aqt.package
|
||||
|
||||
aqt.package.launcher_executable = launcher_executable
|
||||
aqt.package.update_and_restart = update_and_restart
|
||||
aqt.package.trigger_launcher_run = trigger_launcher_run
|
||||
aqt.package.uv_binary = uv_binary
|
||||
aqt.package.launcher_root = launcher_root
|
||||
aqt.package.venv_binary = venv_binary
|
||||
aqt.package.add_python_requirements = add_python_requirements
|
||||
|
||||
|
||||
setup()
|
||||
|
|
|
@ -13,7 +13,7 @@ HOST_ARCH=$(uname -m)
|
|||
|
||||
# Define output paths
|
||||
OUTPUT_DIR="../../../out/launcher"
|
||||
LAUNCHER_DIR="$OUTPUT_DIR/anki-launcher"
|
||||
LAUNCHER_DIR="$OUTPUT_DIR/anki-linux"
|
||||
|
||||
# Clean existing output directory
|
||||
rm -rf "$LAUNCHER_DIR"
|
||||
|
@ -61,6 +61,7 @@ done
|
|||
# Copy additional files from parent directory
|
||||
cp ../pyproject.toml "$LAUNCHER_DIR/"
|
||||
cp ../../../.python-version "$LAUNCHER_DIR/"
|
||||
cp ../versions.py "$LAUNCHER_DIR/"
|
||||
|
||||
# Set executable permissions
|
||||
chmod +x \
|
||||
|
@ -75,10 +76,9 @@ chmod +x \
|
|||
# Set proper permissions and create tarball
|
||||
chmod -R a+r "$LAUNCHER_DIR"
|
||||
|
||||
# Create tarball using the same options as the Rust template
|
||||
ZSTD="zstd -c --long -T0 -18"
|
||||
TRANSFORM="s%^.%anki-launcher%S"
|
||||
TARBALL="$OUTPUT_DIR/anki-launcher.tar.zst"
|
||||
TRANSFORM="s%^.%anki-linux%S"
|
||||
TARBALL="$OUTPUT_DIR/anki-linux.tar.zst"
|
||||
|
||||
tar -I "$ZSTD" --transform "$TRANSFORM" -cf "$TARBALL" -C "$LAUNCHER_DIR" .
|
||||
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>11</string>
|
||||
<string>12</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.education</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
|
|
@ -35,6 +35,7 @@ cp Info.plist "$APP_LAUNCHER/Contents/"
|
|||
cp icon/Assets.car "$APP_LAUNCHER/Contents/Resources/"
|
||||
cp ../pyproject.toml "$APP_LAUNCHER/Contents/Resources/"
|
||||
cp ../../../.python-version "$APP_LAUNCHER/Contents/Resources/"
|
||||
cp ../versions.py "$APP_LAUNCHER/Contents/Resources/"
|
||||
|
||||
# Codesign
|
||||
for i in "$APP_LAUNCHER/Contents/MacOS/uv" "$APP_LAUNCHER/Contents/MacOS/launcher" "$APP_LAUNCHER"; do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "anki-launcher"
|
||||
version = "0.1.0"
|
||||
version = "1.0.0"
|
||||
description = "UV-based launcher for Anki."
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
|
|
|
@ -139,6 +139,9 @@ fn copy_files(output_dir: &Path) -> Result<()> {
|
|||
output_dir.join(".python-version"),
|
||||
)?;
|
||||
|
||||
// Copy versions.py
|
||||
copy_file("../versions.py", output_dir.join("versions.py"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ use anki_process::CommandExt as AnkiCommandExt;
|
|||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::platform::ensure_os_supported;
|
||||
use crate::platform::ensure_terminal_shown;
|
||||
use crate::platform::get_exe_and_resources_dirs;
|
||||
use crate::platform::get_uv_binary_name;
|
||||
|
@ -46,6 +47,7 @@ struct State {
|
|||
uv_lock_path: std::path::PathBuf,
|
||||
sync_complete_marker: std::path::PathBuf,
|
||||
previous_version: Option<String>,
|
||||
resources_dir: std::path::PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -54,6 +56,12 @@ pub enum VersionKind {
|
|||
Uv(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Releases {
|
||||
pub latest: Vec<String>,
|
||||
pub all: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MainMenuChoice {
|
||||
Latest,
|
||||
|
@ -99,6 +107,7 @@ fn run() -> Result<()> {
|
|||
uv_lock_path: uv_install_root.join("uv.lock"),
|
||||
sync_complete_marker: uv_install_root.join(".sync_complete"),
|
||||
previous_version: None,
|
||||
resources_dir,
|
||||
};
|
||||
|
||||
// Check for uninstall request from Windows uninstaller
|
||||
|
@ -110,12 +119,6 @@ fn run() -> Result<()> {
|
|||
|
||||
// Create install directory and copy project files in
|
||||
create_dir_all(&state.uv_install_root)?;
|
||||
let had_user_pyproj = state.user_pyproject_path.exists();
|
||||
if !had_user_pyproj {
|
||||
// during initial launcher testing, enable betas by default
|
||||
write_file(&state.prerelease_marker, "")?;
|
||||
}
|
||||
|
||||
copy_if_newer(&state.dist_pyproject_path, &state.user_pyproject_path)?;
|
||||
copy_if_newer(
|
||||
&state.dist_python_version_path,
|
||||
|
@ -132,7 +135,7 @@ fn run() -> Result<()> {
|
|||
if !pyproject_has_changed {
|
||||
// If venv is already up to date, launch Anki normally
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
let cmd = build_python_command(&state.uv_install_root, &args)?;
|
||||
let cmd = build_python_command(&state, &args)?;
|
||||
launch_anki_normally(cmd)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -143,16 +146,23 @@ fn run() -> Result<()> {
|
|||
print!("\x1B[2J\x1B[H"); // Clear screen and move cursor to top
|
||||
println!("\x1B[1mAnki Launcher\x1B[0m\n");
|
||||
|
||||
ensure_os_supported()?;
|
||||
|
||||
check_versions(&mut state);
|
||||
|
||||
let first_run = !state.uv_install_root.join(".venv").exists();
|
||||
if first_run {
|
||||
handle_version_install_or_update(&state, MainMenuChoice::Latest)?;
|
||||
} else {
|
||||
main_menu_loop(&state)?;
|
||||
}
|
||||
|
||||
// Write marker file to indicate we've completed the sync process
|
||||
write_sync_marker(&state.sync_complete_marker)?;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let cmd = build_python_command(&state.uv_install_root, &[])?;
|
||||
let cmd = build_python_command(&state, &[])?;
|
||||
platform::mac::prepare_for_launch_after_update(cmd, &uv_install_root)?;
|
||||
}
|
||||
|
||||
|
@ -225,9 +235,90 @@ fn check_versions(state: &mut State) {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_version_install_or_update(state: &State, choice: MainMenuChoice) -> Result<()> {
|
||||
update_pyproject_for_version(choice.clone(), state)?;
|
||||
|
||||
// Extract current version before syncing (but don't write to file yet)
|
||||
let previous_version_to_save = extract_aqt_version(&state.uv_path, &state.uv_install_root);
|
||||
|
||||
// Remove sync marker before attempting sync
|
||||
let _ = remove_file(&state.sync_complete_marker);
|
||||
|
||||
println!("\x1B[1mUpdating Anki...\x1B[0m\n");
|
||||
|
||||
let python_version_trimmed = if state.user_python_version_path.exists() {
|
||||
let python_version = read_file(&state.user_python_version_path)?;
|
||||
let python_version_str =
|
||||
String::from_utf8(python_version).context("Invalid UTF-8 in .python-version")?;
|
||||
Some(python_version_str.trim().to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// `uv sync` sometimes does not pull in Python automatically
|
||||
// This might be system/platform specific and/or a uv bug.
|
||||
let mut command = Command::new(&state.uv_path);
|
||||
command
|
||||
.current_dir(&state.uv_install_root)
|
||||
.env("UV_CACHE_DIR", &state.uv_cache_dir)
|
||||
.env("UV_PYTHON_INSTALL_DIR", &state.uv_python_install_dir)
|
||||
.args(["python", "install", "--managed-python"]);
|
||||
|
||||
// Add python version if .python-version file exists
|
||||
if let Some(version) = &python_version_trimmed {
|
||||
command.args([version]);
|
||||
}
|
||||
|
||||
command.ensure_success().context("Python install failed")?;
|
||||
|
||||
// Sync the venv
|
||||
let mut command = Command::new(&state.uv_path);
|
||||
command
|
||||
.current_dir(&state.uv_install_root)
|
||||
.env("UV_CACHE_DIR", &state.uv_cache_dir)
|
||||
.env("UV_PYTHON_INSTALL_DIR", &state.uv_python_install_dir)
|
||||
.args(["sync", "--upgrade", "--managed-python"]);
|
||||
|
||||
// Add python version if .python-version file exists
|
||||
if let Some(version) = &python_version_trimmed {
|
||||
command.args(["--python", version]);
|
||||
}
|
||||
|
||||
if state.no_cache_marker.exists() {
|
||||
command.env("UV_NO_CACHE", "1");
|
||||
}
|
||||
|
||||
match command.ensure_success() {
|
||||
Ok(_) => {
|
||||
// Sync succeeded
|
||||
if matches!(&choice, MainMenuChoice::Version(VersionKind::PyOxidizer(_))) {
|
||||
inject_helper_addon(&state.uv_install_root)?;
|
||||
}
|
||||
|
||||
// Now that sync succeeded, save the previous version
|
||||
if let Some(current_version) = previous_version_to_save {
|
||||
let previous_version_path = state.uv_install_root.join("previous-version");
|
||||
if let Err(e) = write_file(&previous_version_path, ¤t_version) {
|
||||
println!("Warning: Could not save previous version: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
// If sync fails due to things like a missing wheel on pypi,
|
||||
// we need to remove the lockfile or uv will cache the bad result.
|
||||
let _ = remove_file(&state.uv_lock_path);
|
||||
println!("Install failed: {e:#}");
|
||||
println!();
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main_menu_loop(state: &State) -> Result<()> {
|
||||
loop {
|
||||
let menu_choice = get_main_menu_choice(state);
|
||||
let menu_choice = get_main_menu_choice(state)?;
|
||||
|
||||
match menu_choice {
|
||||
MainMenuChoice::Quit => std::process::exit(0),
|
||||
|
@ -270,77 +361,10 @@ fn main_menu_loop(state: &State) -> Result<()> {
|
|||
continue;
|
||||
}
|
||||
choice @ (MainMenuChoice::Latest | MainMenuChoice::Version(_)) => {
|
||||
// For other choices, update project files and sync
|
||||
update_pyproject_for_version(
|
||||
choice.clone(),
|
||||
state.dist_pyproject_path.clone(),
|
||||
state.user_pyproject_path.clone(),
|
||||
state.dist_python_version_path.clone(),
|
||||
state.user_python_version_path.clone(),
|
||||
)?;
|
||||
|
||||
// Extract current version before syncing (but don't write to file yet)
|
||||
let previous_version_to_save =
|
||||
extract_aqt_version(&state.uv_path, &state.uv_install_root);
|
||||
|
||||
// Remove sync marker before attempting sync
|
||||
let _ = remove_file(&state.sync_complete_marker);
|
||||
|
||||
// Sync the venv
|
||||
let mut command = Command::new(&state.uv_path);
|
||||
command
|
||||
.current_dir(&state.uv_install_root)
|
||||
.env("UV_CACHE_DIR", &state.uv_cache_dir)
|
||||
.env("UV_PYTHON_INSTALL_DIR", &state.uv_python_install_dir)
|
||||
.args(["sync", "--upgrade", "--managed-python"]);
|
||||
|
||||
// Add python version if .python-version file exists
|
||||
if state.user_python_version_path.exists() {
|
||||
let python_version = read_file(&state.user_python_version_path)?;
|
||||
let python_version_str = String::from_utf8(python_version)
|
||||
.context("Invalid UTF-8 in .python-version")?;
|
||||
let python_version_trimmed = python_version_str.trim();
|
||||
command.args(["--python", python_version_trimmed]);
|
||||
}
|
||||
|
||||
// Set UV_PRERELEASE=allow if beta mode is enabled
|
||||
if state.prerelease_marker.exists() {
|
||||
command.env("UV_PRERELEASE", "allow");
|
||||
}
|
||||
|
||||
if state.no_cache_marker.exists() {
|
||||
command.env("UV_NO_CACHE", "1");
|
||||
}
|
||||
|
||||
println!("\x1B[1mUpdating Anki...\x1B[0m\n");
|
||||
|
||||
match command.ensure_success() {
|
||||
Ok(_) => {
|
||||
// Sync succeeded
|
||||
if matches!(&choice, MainMenuChoice::Version(VersionKind::PyOxidizer(_))) {
|
||||
inject_helper_addon(&state.uv_install_root)?;
|
||||
}
|
||||
|
||||
// Now that sync succeeded, save the previous version
|
||||
if let Some(current_version) = previous_version_to_save {
|
||||
let previous_version_path =
|
||||
state.uv_install_root.join("previous-version");
|
||||
if let Err(e) = write_file(&previous_version_path, ¤t_version) {
|
||||
println!("Warning: Could not save previous version: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
// If sync fails due to things like a missing wheel on pypi,
|
||||
// we need to remove the lockfile or uv will cache the bad result.
|
||||
let _ = remove_file(&state.uv_lock_path);
|
||||
println!("Install failed: {e:#}");
|
||||
println!();
|
||||
if handle_version_install_or_update(state, choice.clone()).is_err() {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,16 +380,18 @@ fn write_sync_marker(sync_complete_marker: &std::path::Path) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_main_menu_choice(state: &State) -> MainMenuChoice {
|
||||
fn get_main_menu_choice(state: &State) -> Result<MainMenuChoice> {
|
||||
loop {
|
||||
println!("1) Latest Anki (just press enter)");
|
||||
println!("1) Latest Anki (press Enter)");
|
||||
println!("2) Choose a version");
|
||||
if let Some(current_version) = &state.current_version {
|
||||
println!("3) Keep existing version ({current_version})");
|
||||
let normalized_current = normalize_version(current_version);
|
||||
println!("3) Keep existing version ({normalized_current})");
|
||||
}
|
||||
if let Some(prev_version) = &state.previous_version {
|
||||
if state.current_version.as_ref() != Some(prev_version) {
|
||||
println!("4) Revert to previous version ({prev_version})");
|
||||
let normalized_prev = normalize_version(prev_version);
|
||||
println!("4) Revert to previous version ({normalized_prev})");
|
||||
}
|
||||
}
|
||||
println!();
|
||||
|
@ -392,9 +418,14 @@ fn get_main_menu_choice(state: &State) -> MainMenuChoice {
|
|||
|
||||
println!();
|
||||
|
||||
return match input {
|
||||
return Ok(match input {
|
||||
"" | "1" => MainMenuChoice::Latest,
|
||||
"2" => MainMenuChoice::Version(get_version_kind()),
|
||||
"2" => {
|
||||
match get_version_kind(state)? {
|
||||
Some(version_kind) => MainMenuChoice::Version(version_kind),
|
||||
None => continue, // Return to main menu
|
||||
}
|
||||
}
|
||||
"3" => {
|
||||
if state.current_version.is_some() {
|
||||
MainMenuChoice::KeepExisting
|
||||
|
@ -407,7 +438,7 @@ fn get_main_menu_choice(state: &State) -> MainMenuChoice {
|
|||
if let Some(prev_version) = &state.previous_version {
|
||||
if state.current_version.as_ref() != Some(prev_version) {
|
||||
if let Some(version_kind) = parse_version_kind(prev_version) {
|
||||
return MainMenuChoice::Version(version_kind);
|
||||
return Ok(MainMenuChoice::Version(version_kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -422,12 +453,22 @@ fn get_main_menu_choice(state: &State) -> MainMenuChoice {
|
|||
println!("Invalid input. Please try again.");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn get_version_kind() -> VersionKind {
|
||||
loop {
|
||||
fn get_version_kind(state: &State) -> Result<Option<VersionKind>> {
|
||||
println!("Please wait...");
|
||||
|
||||
let releases = get_releases(state)?;
|
||||
let releases_str = releases
|
||||
.latest
|
||||
.iter()
|
||||
.map(|v| v.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
println!("Latest releases: {releases_str}");
|
||||
|
||||
println!("Enter the version you want to install:");
|
||||
print!("> ");
|
||||
let _ = stdout().flush();
|
||||
|
@ -437,54 +478,171 @@ fn get_version_kind() -> VersionKind {
|
|||
let input = input.trim();
|
||||
|
||||
if input.is_empty() {
|
||||
println!("Please enter a version.");
|
||||
continue;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
match parse_version_kind(input) {
|
||||
Some(version_kind) => {
|
||||
// Normalize the input version for comparison
|
||||
let normalized_input = normalize_version(input);
|
||||
|
||||
// Check if the version exists in the available versions
|
||||
let version_exists = releases.all.iter().any(|v| v == &normalized_input);
|
||||
|
||||
match (parse_version_kind(input), version_exists) {
|
||||
(Some(version_kind), true) => {
|
||||
println!();
|
||||
return version_kind;
|
||||
Ok(Some(version_kind))
|
||||
}
|
||||
None => {
|
||||
println!("Invalid version format. Please enter a version like 24.10 or 25.06.1 (minimum 2.1.50)");
|
||||
continue;
|
||||
(None, true) => {
|
||||
println!("Versions before 2.1.50 can't be installed.");
|
||||
Ok(None)
|
||||
}
|
||||
_ => {
|
||||
println!("Invalid version.\n");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_pyproject_for_version(
|
||||
menu_choice: MainMenuChoice,
|
||||
dist_pyproject_path: std::path::PathBuf,
|
||||
user_pyproject_path: std::path::PathBuf,
|
||||
dist_python_version_path: std::path::PathBuf,
|
||||
user_python_version_path: std::path::PathBuf,
|
||||
) -> Result<()> {
|
||||
match menu_choice {
|
||||
MainMenuChoice::Latest => {
|
||||
let content = read_file(&dist_pyproject_path)?;
|
||||
write_file(&user_pyproject_path, &content)?;
|
||||
let python_version_content = read_file(&dist_python_version_path)?;
|
||||
write_file(&user_python_version_path, &python_version_content)?;
|
||||
fn with_only_latest_patch(versions: &[String]) -> Vec<String> {
|
||||
// Only show the latest patch release for a given (major, minor)
|
||||
let mut seen_major_minor = std::collections::HashSet::new();
|
||||
versions
|
||||
.iter()
|
||||
.filter(|v| {
|
||||
let (major, minor, _, _) = parse_version_for_filtering(v);
|
||||
if major == 2 {
|
||||
return true;
|
||||
}
|
||||
MainMenuChoice::KeepExisting => {
|
||||
// Do nothing - keep existing pyproject.toml and .python-version
|
||||
let major_minor = (major, minor);
|
||||
if seen_major_minor.contains(&major_minor) {
|
||||
false
|
||||
} else {
|
||||
seen_major_minor.insert(major_minor);
|
||||
true
|
||||
}
|
||||
MainMenuChoice::ToggleBetas => {
|
||||
unreachable!();
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
MainMenuChoice::ToggleCache => {
|
||||
unreachable!();
|
||||
|
||||
fn parse_version_for_filtering(version_str: &str) -> (u32, u32, u32, bool) {
|
||||
// Remove any build metadata after +
|
||||
let version_str = version_str.split('+').next().unwrap_or(version_str);
|
||||
|
||||
// Check for prerelease markers
|
||||
let is_prerelease = ["a", "b", "rc", "alpha", "beta"]
|
||||
.iter()
|
||||
.any(|marker| version_str.to_lowercase().contains(marker));
|
||||
|
||||
// Extract numeric parts (stop at first non-digit/non-dot character)
|
||||
let numeric_end = version_str
|
||||
.find(|c: char| !c.is_ascii_digit() && c != '.')
|
||||
.unwrap_or(version_str.len());
|
||||
let numeric_part = &version_str[..numeric_end];
|
||||
|
||||
let parts: Vec<&str> = numeric_part.split('.').collect();
|
||||
|
||||
let major = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||
let minor = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||
let patch = parts.get(2).and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||
|
||||
(major, minor, patch, is_prerelease)
|
||||
}
|
||||
MainMenuChoice::Uninstall => {
|
||||
unreachable!();
|
||||
|
||||
fn normalize_version(version: &str) -> String {
|
||||
let (major, minor, patch, _is_prerelease) = parse_version_for_filtering(version);
|
||||
|
||||
if major <= 2 {
|
||||
// Don't transform versions <= 2.x
|
||||
return version.to_string();
|
||||
}
|
||||
MainMenuChoice::Version(version_kind) => {
|
||||
let content = read_file(&dist_pyproject_path)?;
|
||||
let content_str =
|
||||
String::from_utf8(content).context("Invalid UTF-8 in pyproject.toml")?;
|
||||
let updated_content = match &version_kind {
|
||||
|
||||
// For versions > 2, pad the minor version with leading zero if < 10
|
||||
let normalized_minor = if minor < 10 {
|
||||
format!("0{minor}")
|
||||
} else {
|
||||
minor.to_string()
|
||||
};
|
||||
|
||||
// Find any prerelease suffix
|
||||
let mut prerelease_suffix = "";
|
||||
|
||||
// Look for prerelease markers after the numeric part
|
||||
let numeric_end = version
|
||||
.find(|c: char| !c.is_ascii_digit() && c != '.')
|
||||
.unwrap_or(version.len());
|
||||
if numeric_end < version.len() {
|
||||
let suffix_part = &version[numeric_end..];
|
||||
let suffix_lower = suffix_part.to_lowercase();
|
||||
|
||||
for marker in ["alpha", "beta", "rc", "a", "b"] {
|
||||
if suffix_lower.starts_with(marker) {
|
||||
prerelease_suffix = &version[numeric_end..];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reconstruct the version
|
||||
if version.matches('.').count() >= 2 {
|
||||
format!("{major}.{normalized_minor}.{patch}{prerelease_suffix}")
|
||||
} else {
|
||||
format!("{major}.{normalized_minor}{prerelease_suffix}")
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_and_normalize_versions(
|
||||
all_versions: Vec<String>,
|
||||
include_prereleases: bool,
|
||||
) -> Vec<String> {
|
||||
let mut valid_versions: Vec<String> = all_versions
|
||||
.into_iter()
|
||||
.map(|v| normalize_version(&v))
|
||||
.collect();
|
||||
|
||||
// Reverse to get chronological order (newest first)
|
||||
valid_versions.reverse();
|
||||
|
||||
if !include_prereleases {
|
||||
valid_versions.retain(|v| {
|
||||
let (_, _, _, is_prerelease) = parse_version_for_filtering(v);
|
||||
!is_prerelease
|
||||
});
|
||||
}
|
||||
|
||||
valid_versions
|
||||
}
|
||||
|
||||
fn fetch_versions(state: &State) -> Result<Vec<String>> {
|
||||
let versions_script = state.resources_dir.join("versions.py");
|
||||
|
||||
let mut cmd = Command::new(&state.uv_path);
|
||||
cmd.current_dir(&state.uv_install_root)
|
||||
.args(["run", "--no-project"])
|
||||
.arg(&versions_script);
|
||||
|
||||
let output = cmd.utf8_output()?;
|
||||
let versions = serde_json::from_str(&output.stdout).context("Failed to parse versions JSON")?;
|
||||
Ok(versions)
|
||||
}
|
||||
|
||||
fn get_releases(state: &State) -> Result<Releases> {
|
||||
let include_prereleases = state.prerelease_marker.exists();
|
||||
let all_versions = fetch_versions(state)?;
|
||||
let all_versions = filter_and_normalize_versions(all_versions, include_prereleases);
|
||||
|
||||
let latest_patches = with_only_latest_patch(&all_versions);
|
||||
let latest_releases: Vec<String> = latest_patches.into_iter().take(5).collect();
|
||||
Ok(Releases {
|
||||
latest: latest_releases,
|
||||
all: all_versions,
|
||||
})
|
||||
}
|
||||
|
||||
fn apply_version_kind(version_kind: &VersionKind, state: &State) -> Result<()> {
|
||||
let content = read_file(&state.dist_pyproject_path)?;
|
||||
let content_str = String::from_utf8(content).context("Invalid UTF-8 in pyproject.toml")?;
|
||||
let updated_content = match version_kind {
|
||||
VersionKind::PyOxidizer(version) => {
|
||||
// Replace package name and add PyQt6 dependencies
|
||||
content_str.replace(
|
||||
|
@ -503,21 +661,50 @@ fn update_pyproject_for_version(
|
|||
),
|
||||
)
|
||||
}
|
||||
VersionKind::Uv(version) => {
|
||||
content_str.replace("anki-release", &format!("anki-release=={version}"))
|
||||
}
|
||||
VersionKind::Uv(version) => content_str.replace(
|
||||
"anki-release",
|
||||
&format!("anki-release=={version}\",\n \"anki=={version}\",\n \"aqt=={version}"),
|
||||
),
|
||||
};
|
||||
write_file(&user_pyproject_path, &updated_content)?;
|
||||
write_file(&state.user_pyproject_path, &updated_content)?;
|
||||
|
||||
// Update .python-version based on version kind
|
||||
match &version_kind {
|
||||
match version_kind {
|
||||
VersionKind::PyOxidizer(_) => {
|
||||
write_file(&user_python_version_path, "3.9")?;
|
||||
write_file(&state.user_python_version_path, "3.9")?;
|
||||
}
|
||||
VersionKind::Uv(_) => {
|
||||
copy_file(&dist_python_version_path, &user_python_version_path)?;
|
||||
copy_file(
|
||||
&state.dist_python_version_path,
|
||||
&state.user_python_version_path,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_pyproject_for_version(menu_choice: MainMenuChoice, state: &State) -> Result<()> {
|
||||
match menu_choice {
|
||||
MainMenuChoice::Latest => {
|
||||
// Get the latest release version and create a VersionKind for it
|
||||
let releases = get_releases(state)?;
|
||||
let latest_version = releases.latest.first().context("No latest version found")?;
|
||||
apply_version_kind(&VersionKind::Uv(latest_version.clone()), state)?;
|
||||
}
|
||||
MainMenuChoice::KeepExisting => {
|
||||
// Do nothing - keep existing pyproject.toml and .python-version
|
||||
}
|
||||
MainMenuChoice::ToggleBetas => {
|
||||
unreachable!();
|
||||
}
|
||||
MainMenuChoice::ToggleCache => {
|
||||
unreachable!();
|
||||
}
|
||||
MainMenuChoice::Uninstall => {
|
||||
unreachable!();
|
||||
}
|
||||
MainMenuChoice::Version(version_kind) => {
|
||||
apply_version_kind(&version_kind, state)?;
|
||||
}
|
||||
MainMenuChoice::Quit => {
|
||||
std::process::exit(0);
|
||||
|
@ -671,24 +858,54 @@ fn handle_uninstall(state: &State) -> Result<bool> {
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
fn build_python_command(uv_install_root: &std::path::Path, args: &[String]) -> Result<Command> {
|
||||
fn build_python_command(state: &State, args: &[String]) -> Result<Command> {
|
||||
let python_exe = if cfg!(target_os = "windows") {
|
||||
let show_console = std::env::var("ANKI_CONSOLE").is_ok();
|
||||
if show_console {
|
||||
uv_install_root.join(".venv/Scripts/python.exe")
|
||||
state.uv_install_root.join(".venv/Scripts/python.exe")
|
||||
} else {
|
||||
uv_install_root.join(".venv/Scripts/pythonw.exe")
|
||||
state.uv_install_root.join(".venv/Scripts/pythonw.exe")
|
||||
}
|
||||
} else {
|
||||
uv_install_root.join(".venv/bin/python")
|
||||
state.uv_install_root.join(".venv/bin/python")
|
||||
};
|
||||
|
||||
let mut cmd = Command::new(python_exe);
|
||||
let mut cmd = Command::new(&python_exe);
|
||||
cmd.args(["-c", "import aqt, sys; sys.argv[0] = 'Anki'; aqt.run()"]);
|
||||
cmd.args(args);
|
||||
// tell the Python code it was invoked by the launcher, and updating is
|
||||
// available
|
||||
cmd.env("ANKI_LAUNCHER", std::env::current_exe()?.utf8()?.as_str());
|
||||
|
||||
// Set UV and Python paths for the Python code
|
||||
cmd.env("ANKI_LAUNCHER_UV", state.uv_path.utf8()?.as_str());
|
||||
cmd.env("UV_PROJECT", state.uv_install_root.utf8()?.as_str());
|
||||
|
||||
Ok(cmd)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_normalize_version() {
|
||||
// Test versions <= 2.x (should not be transformed)
|
||||
assert_eq!(normalize_version("2.1.50"), "2.1.50");
|
||||
|
||||
// Test basic versions > 2 with zero-padding
|
||||
assert_eq!(normalize_version("25.7"), "25.07");
|
||||
assert_eq!(normalize_version("25.07"), "25.07");
|
||||
assert_eq!(normalize_version("25.10"), "25.10");
|
||||
assert_eq!(normalize_version("24.6.1"), "24.06.1");
|
||||
assert_eq!(normalize_version("24.06.1"), "24.06.1");
|
||||
|
||||
// Test prerelease versions
|
||||
assert_eq!(normalize_version("25.7a1"), "25.07a1");
|
||||
assert_eq!(normalize_version("25.7.1a1"), "25.07.1a1");
|
||||
|
||||
// Test versions with patch = 0
|
||||
assert_eq!(normalize_version("25.7.0"), "25.07.0");
|
||||
assert_eq!(normalize_version("25.7.0a1"), "25.07.0a1");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,3 +128,10 @@ pub fn ensure_terminal_shown() -> Result<()> {
|
|||
print!("\x1b]2;Anki Launcher\x07");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn ensure_os_supported() -> Result<()> {
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
unix::ensure_glibc_supported()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -9,15 +9,22 @@ use anyhow::Result;
|
|||
pub fn relaunch_in_terminal() -> Result<()> {
|
||||
let current_exe = std::env::current_exe().context("Failed to get current executable path")?;
|
||||
|
||||
// Try terminals in order of preference
|
||||
// Try terminals in roughly most specific to least specific.
|
||||
// First, try commonly used terminals for riced systems.
|
||||
// Second, try common defaults.
|
||||
// Finally, try x11 compatibility terminals.
|
||||
let terminals = [
|
||||
("x-terminal-emulator", vec!["-e"]),
|
||||
("gnome-terminal", vec!["--"]),
|
||||
("konsole", vec!["-e"]),
|
||||
("xfce4-terminal", vec!["-e"]),
|
||||
// commonly used for riced systems
|
||||
("alacritty", vec!["-e"]),
|
||||
("kitty", vec![]),
|
||||
("foot", vec![]),
|
||||
// the user's default terminal in Debian/Ubuntu
|
||||
("x-terminal-emulator", vec!["-e"]),
|
||||
// default installs for the most common distros
|
||||
("xfce4-terminal", vec!["-e"]),
|
||||
("gnome-terminal", vec!["-e"]),
|
||||
("konsole", vec!["-e"]),
|
||||
// x11-compatibility terminals
|
||||
("urxvt", vec!["-e"]),
|
||||
("xterm", vec!["-e"]),
|
||||
];
|
||||
|
@ -65,3 +72,34 @@ pub fn finalize_uninstall() {
|
|||
let mut input = String::new();
|
||||
let _ = stdin().read_line(&mut input);
|
||||
}
|
||||
|
||||
pub fn ensure_glibc_supported() -> Result<()> {
|
||||
use std::ffi::CStr;
|
||||
let get_glibc_version = || -> Option<(u32, u32)> {
|
||||
let version_ptr = unsafe { libc::gnu_get_libc_version() };
|
||||
if version_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let version_cstr = unsafe { CStr::from_ptr(version_ptr) };
|
||||
let version_str = version_cstr.to_str().ok()?;
|
||||
|
||||
// Parse version string (format: "2.36" or "2.36.1")
|
||||
let version_parts: Vec<&str> = version_str.split('.').collect();
|
||||
if version_parts.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let major: u32 = version_parts[0].parse().ok()?;
|
||||
let minor: u32 = version_parts[1].parse().ok()?;
|
||||
|
||||
Some((major, minor))
|
||||
};
|
||||
|
||||
let (major, minor) = get_glibc_version().unwrap_or_default();
|
||||
if major < 2 || (major == 2 && minor < 36) {
|
||||
anyhow::bail!("Anki requires a modern Linux distro with glibc 2.36 or later.");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
39
qt/launcher/versions.py
Normal file
39
qt/launcher/versions.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import json
|
||||
import sys
|
||||
import urllib.request
|
||||
|
||||
|
||||
def main():
|
||||
"""Fetch and return all versions from PyPI, sorted by upload time."""
|
||||
url = "https://pypi.org/pypi/aqt/json"
|
||||
|
||||
try:
|
||||
with urllib.request.urlopen(url, timeout=30) as response:
|
||||
data = json.loads(response.read().decode("utf-8"))
|
||||
releases = data.get("releases", {})
|
||||
|
||||
# Create list of (version, upload_time) tuples
|
||||
version_times = []
|
||||
for version, files in releases.items():
|
||||
if files: # Only include versions that have files
|
||||
# Use the upload time of the first file for each version
|
||||
upload_time = files[0].get("upload_time_iso_8601")
|
||||
if upload_time:
|
||||
version_times.append((version, upload_time))
|
||||
|
||||
# Sort by upload time
|
||||
version_times.sort(key=lambda x: x[1])
|
||||
|
||||
# Extract just the version names
|
||||
versions = [version for version, _ in version_times]
|
||||
print(json.dumps(versions))
|
||||
except Exception as e:
|
||||
print(f"Error fetching versions: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -37,14 +37,14 @@ qt67 = [
|
|||
"pyqt6-webengine-qt6==6.7.3",
|
||||
"pyqt6_sip==13.10.2",
|
||||
]
|
||||
qt69 = [
|
||||
qt = [
|
||||
"pyqt6==6.9.1",
|
||||
"pyqt6-qt6==6.9.1",
|
||||
"pyqt6-webengine==6.9.0",
|
||||
"pyqt6-webengine-qt6==6.9.1",
|
||||
"pyqt6_sip==13.10.2",
|
||||
]
|
||||
qt = [
|
||||
qt68 = [
|
||||
"pyqt6==6.8.0",
|
||||
"pyqt6-qt6==6.8.1",
|
||||
"pyqt6-webengine==6.8.0",
|
||||
|
@ -58,7 +58,7 @@ conflicts = [
|
|||
{ extra = "qt" },
|
||||
{ extra = "qt66" },
|
||||
{ extra = "qt67" },
|
||||
{ extra = "qt69" },
|
||||
{ extra = "qt68" },
|
||||
],
|
||||
]
|
||||
|
||||
|
@ -72,9 +72,12 @@ build-backend = "hatchling.build"
|
|||
[project.scripts]
|
||||
anki = "aqt:run"
|
||||
|
||||
[project.gui-scripts]
|
||||
ankiw = "aqt:run"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["aqt"]
|
||||
exclude = ["**/*.scss", "**/*.ui"]
|
||||
exclude = ["aqt/data", "**/*.ui"]
|
||||
|
||||
[tool.hatch.version]
|
||||
source = "code"
|
||||
|
|
|
@ -48,6 +48,7 @@ async-trait.workspace = true
|
|||
axum.workspace = true
|
||||
axum-client-ip.workspace = true
|
||||
axum-extra.workspace = true
|
||||
bitflags.workspace = true
|
||||
blake3.workspace = true
|
||||
bytes.workspace = true
|
||||
chrono.workspace = true
|
||||
|
|
|
@ -39,6 +39,7 @@ impl From<BoolKeyProto> for BoolKey {
|
|||
BoolKeyProto::RenderLatex => BoolKey::RenderLatex,
|
||||
BoolKeyProto::LoadBalancerEnabled => BoolKey::LoadBalancerEnabled,
|
||||
BoolKeyProto::FsrsShortTermWithStepsEnabled => BoolKey::FsrsShortTermWithStepsEnabled,
|
||||
BoolKeyProto::FsrsLegacyEvaluate => BoolKey::FsrsLegacyEvaluate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,9 @@ impl Card {
|
|||
/// This uses card.due and card.ivl to infer the elapsed time. If 'set due
|
||||
/// date' or an add-on has changed the due date, this won't be accurate.
|
||||
pub(crate) fn days_since_last_review(&self, timing: &SchedTimingToday) -> Option<u32> {
|
||||
if !self.is_due_in_days() {
|
||||
if let Some(last_review_time) = self.last_review_time {
|
||||
Some(timing.next_day_at.elapsed_days_since(last_review_time) as u32)
|
||||
} else if !self.is_due_in_days() {
|
||||
Some(
|
||||
(timing.next_day_at.0 as u32).saturating_sub(self.original_or_current_due() as u32)
|
||||
/ 86_400,
|
||||
|
|
|
@ -96,6 +96,7 @@ pub struct Card {
|
|||
pub(crate) memory_state: Option<FsrsMemoryState>,
|
||||
pub(crate) desired_retention: Option<f32>,
|
||||
pub(crate) decay: Option<f32>,
|
||||
pub(crate) last_review_time: Option<TimestampSecs>,
|
||||
/// JSON object or empty; exposed through the reviewer for persisting custom
|
||||
/// state
|
||||
pub(crate) custom_data: String,
|
||||
|
@ -147,6 +148,7 @@ impl Default for Card {
|
|||
memory_state: None,
|
||||
desired_retention: None,
|
||||
decay: None,
|
||||
last_review_time: None,
|
||||
custom_data: String::new(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ impl TryFrom<anki_proto::cards::Card> for Card {
|
|||
memory_state: c.memory_state.map(Into::into),
|
||||
desired_retention: c.desired_retention,
|
||||
decay: c.decay,
|
||||
last_review_time: c.last_review_time_secs.map(TimestampSecs),
|
||||
custom_data: c.custom_data,
|
||||
})
|
||||
}
|
||||
|
@ -136,6 +137,7 @@ impl From<Card> for anki_proto::cards::Card {
|
|||
memory_state: c.memory_state.map(Into::into),
|
||||
desired_retention: c.desired_retention,
|
||||
decay: c.decay,
|
||||
last_review_time_secs: c.last_review_time.map(|t| t.0),
|
||||
custom_data: c.custom_data,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ use crate::latex::contains_latex;
|
|||
use crate::template::RenderContext;
|
||||
use crate::text::strip_html_preserving_entities;
|
||||
|
||||
static CLOZE: LazyLock<Regex> =
|
||||
LazyLock::new(|| Regex::new(r"(?s)\{\{c\d+::(.*?)(::.*?)?\}\}").unwrap());
|
||||
|
||||
static MATHJAX: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(
|
||||
r"(?xsi)
|
||||
|
@ -453,6 +456,10 @@ pub fn cloze_number_in_fields(fields: impl IntoIterator<Item: AsRef<str>>) -> Ha
|
|||
set
|
||||
}
|
||||
|
||||
pub(crate) fn strip_clozes(text: &str) -> Cow<'_, str> {
|
||||
CLOZE.replace_all(text, "$1")
|
||||
}
|
||||
|
||||
fn strip_html_inside_mathjax(text: &str) -> Cow<str> {
|
||||
MATHJAX.replace_all(text, |caps: &Captures| -> String {
|
||||
format!(
|
||||
|
@ -610,6 +617,16 @@ mod test {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strip_clozes_regex() {
|
||||
assert_eq!(
|
||||
strip_clozes(
|
||||
r#"The {{c1::moon::🌛}} {{c2::orbits::this hint has "::" in it}} the {{c3::🌏}}."#
|
||||
),
|
||||
"The moon orbits the 🌏."
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mathjax_html() {
|
||||
// escaped angle brackets should be preserved
|
||||
|
|
|
@ -41,6 +41,7 @@ pub enum BoolKey {
|
|||
WithDeckConfigs,
|
||||
Fsrs,
|
||||
FsrsHealthCheck,
|
||||
FsrsLegacyEvaluate,
|
||||
LoadBalancerEnabled,
|
||||
FsrsShortTermWithStepsEnabled,
|
||||
#[strum(to_string = "normalize_note_text")]
|
||||
|
|
|
@ -74,6 +74,7 @@ impl Collection {
|
|||
apply_all_parent_limits: self.get_config_bool(BoolKey::ApplyAllParentLimits),
|
||||
fsrs: self.get_config_bool(BoolKey::Fsrs),
|
||||
fsrs_health_check: self.get_config_bool(BoolKey::FsrsHealthCheck),
|
||||
fsrs_legacy_evaluate: self.get_config_bool(BoolKey::FsrsLegacyEvaluate),
|
||||
days_since_last_fsrs_optimize,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ impl Collection {
|
|||
let card_count = match deck.kind {
|
||||
DeckKind::Normal(_) => self.delete_all_cards_in_normal_deck(deck.id)?,
|
||||
DeckKind::Filtered(_) => {
|
||||
self.return_all_cards_in_filtered_deck(deck.id)?;
|
||||
self.return_all_cards_in_filtered_deck(deck)?;
|
||||
0
|
||||
}
|
||||
};
|
||||
|
|
|
@ -61,6 +61,7 @@ impl CsvDeckExt for CsvDeck {
|
|||
match self {
|
||||
Self::DeckId(did) => NameOrId::Id(*did),
|
||||
Self::DeckColumn(_) => NameOrId::default(),
|
||||
Self::DeckName(name) => NameOrId::Name(name.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +69,7 @@ impl CsvDeckExt for CsvDeck {
|
|||
match self {
|
||||
Self::DeckId(_) => None,
|
||||
Self::DeckColumn(column) => Some(*column as usize),
|
||||
Self::DeckName(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,6 +163,8 @@ impl Collection {
|
|||
"deck" => {
|
||||
if let Ok(Some(did)) = self.deck_id_by_name_or_id(&NameOrId::parse(value)) {
|
||||
metadata.deck = Some(CsvDeck::DeckId(did.0));
|
||||
} else if !value.is_empty() {
|
||||
metadata.deck = Some(CsvDeck::DeckName(value.to_string()));
|
||||
}
|
||||
}
|
||||
"notetype column" => {
|
||||
|
@ -626,6 +628,7 @@ pub(in crate::import_export) mod test {
|
|||
pub trait CsvMetadataTestExt {
|
||||
fn defaults_for_testing() -> Self;
|
||||
fn unwrap_deck_id(&self) -> i64;
|
||||
fn unwrap_deck_name(&self) -> &str;
|
||||
fn unwrap_notetype_id(&self) -> i64;
|
||||
fn unwrap_notetype_map(&self) -> &[u32];
|
||||
}
|
||||
|
@ -660,6 +663,13 @@ pub(in crate::import_export) mod test {
|
|||
}
|
||||
}
|
||||
|
||||
fn unwrap_deck_name(&self) -> &str {
|
||||
match &self.deck {
|
||||
Some(CsvDeck::DeckName(name)) => name,
|
||||
_ => panic!("no deck name"),
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_notetype_id(&self) -> i64 {
|
||||
match self.notetype {
|
||||
Some(CsvNotetype::GlobalNotetype(ref nt)) => nt.id,
|
||||
|
@ -683,8 +693,11 @@ pub(in crate::import_export) mod test {
|
|||
metadata!(col, format!("#deck:{deck_id}\n")).unwrap_deck_id(),
|
||||
deck_id
|
||||
);
|
||||
// unknown deck
|
||||
assert_eq!(metadata!(col, "#deck:foo\n").unwrap_deck_name(), "foo");
|
||||
assert_eq!(metadata!(col, "#deck:1234\n").unwrap_deck_name(), "1234");
|
||||
// fallback
|
||||
assert_eq!(metadata!(col, "#deck:foo\n").unwrap_deck_id(), 1);
|
||||
assert_eq!(metadata!(col, "#deck:\n").unwrap_deck_id(), 1);
|
||||
assert_eq!(metadata!(col, "\n").unwrap_deck_id(), 1);
|
||||
}
|
||||
|
||||
|
@ -726,8 +739,8 @@ pub(in crate::import_export) mod test {
|
|||
numeric_deck_2_id
|
||||
);
|
||||
assert_eq!(
|
||||
metadata!(col, format!("#deck:1234\n")).unwrap_deck_id(),
|
||||
1 // default deck
|
||||
metadata!(col, format!("#deck:1234\n")).unwrap_deck_name(),
|
||||
"1234"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ impl Duplicate {
|
|||
}
|
||||
|
||||
impl DeckIdsByNameOrId {
|
||||
fn new(col: &mut Collection, default: &NameOrId) -> Result<Self> {
|
||||
fn new(col: &mut Collection, default: &NameOrId, usn: Usn) -> Result<Self> {
|
||||
let names: HashMap<UniCase<String>, DeckId> = col
|
||||
.get_all_normal_deck_names(false)?
|
||||
.into_iter()
|
||||
|
@ -160,6 +160,13 @@ impl DeckIdsByNameOrId {
|
|||
default: None,
|
||||
};
|
||||
new.default = new.get(default);
|
||||
if new.default.is_none() && *default != NameOrId::default() {
|
||||
let mut deck = Deck::new_normal();
|
||||
deck.name = NativeDeckName::from_human_name(default.to_string());
|
||||
col.add_deck_inner(&mut deck, usn)?;
|
||||
new.insert(deck.id, deck.human_name());
|
||||
new.default = Some(deck.id);
|
||||
}
|
||||
|
||||
Ok(new)
|
||||
}
|
||||
|
@ -193,7 +200,7 @@ impl<'a> Context<'a> {
|
|||
NameOrId::default(),
|
||||
col.notetype_by_name_or_id(&data.default_notetype)?,
|
||||
);
|
||||
let deck_ids = DeckIdsByNameOrId::new(col, &data.default_deck)?;
|
||||
let deck_ids = DeckIdsByNameOrId::new(col, &data.default_deck, usn)?;
|
||||
let existing_checksums = ExistingChecksums::new(col, data.match_scope)?;
|
||||
let existing_guids = col.storage.all_notes_by_guid()?;
|
||||
|
||||
|
@ -274,6 +281,9 @@ impl<'a> Context<'a> {
|
|||
deck.name = NativeDeckName::from_human_name(name);
|
||||
self.col.add_deck_inner(&mut deck, self.usn)?;
|
||||
self.deck_ids.insert(deck.id, deck.human_name());
|
||||
if name.is_empty() {
|
||||
self.deck_ids.default = Some(deck.id);
|
||||
}
|
||||
Some(deck.id)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -83,6 +83,15 @@ impl From<String> for NameOrId {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NameOrId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
NameOrId::Id(did) => write!(f, "{did}"),
|
||||
NameOrId::Name(name) => write!(f, "{name}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignNote {
|
||||
pub(crate) fn into_log_note(self) -> LogNote {
|
||||
LogNote {
|
||||
|
|
|
@ -228,28 +228,31 @@ impl Collection {
|
|||
/// Return the next states that will be applied for each answer button.
|
||||
pub fn get_scheduling_states(&mut self, cid: CardId) -> Result<SchedulingStates> {
|
||||
let card = self.storage.get_card(cid)?.or_not_found(cid)?;
|
||||
let deck = self.get_deck(card.deck_id)?.or_not_found(card.deck_id)?;
|
||||
|
||||
let note_id = deck
|
||||
.config_id()
|
||||
.map(|deck_config_id| self.get_deck_config(deck_config_id, false))
|
||||
.transpose()?
|
||||
.flatten()
|
||||
.map(|deck_config| deck_config.inner.bury_reviews)
|
||||
.unwrap_or(false)
|
||||
.then_some(card.note_id);
|
||||
let note_id = card.note_id;
|
||||
|
||||
let ctx = self.card_state_updater(card)?;
|
||||
let current = ctx.current_card_state();
|
||||
|
||||
let load_balancer_ctx = self.state.card_queues.as_ref().and_then(|card_queues| {
|
||||
match card_queues.load_balancer.as_ref() {
|
||||
None => None,
|
||||
Some(load_balancer) => {
|
||||
Some(load_balancer.review_context(note_id, deck.config_id()?))
|
||||
let load_balancer_ctx = if let Some(load_balancer) = self
|
||||
.state
|
||||
.card_queues
|
||||
.as_ref()
|
||||
.and_then(|card_queues| card_queues.load_balancer.as_ref())
|
||||
{
|
||||
// Only get_deck_config when load balancer is enabled
|
||||
if let Some(deck_config_id) = ctx.deck.config_id() {
|
||||
let note_id = self
|
||||
.get_deck_config(deck_config_id, false)?
|
||||
.map(|deck_config| deck_config.inner.bury_reviews)
|
||||
.unwrap_or(false)
|
||||
.then_some(note_id);
|
||||
Some(load_balancer.review_context(note_id, deck_config_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let state_ctx = ctx.state_context(load_balancer_ctx);
|
||||
Ok(current.next_states(&state_ctx))
|
||||
|
@ -334,7 +337,14 @@ impl Collection {
|
|||
self.update_deck_stats_from_answer(usn, answer, &updater, original.queue)?;
|
||||
self.maybe_bury_siblings(&original, &updater.config)?;
|
||||
let timing = updater.timing;
|
||||
let deckconfig_id = updater.deck.config_id();
|
||||
let mut card = updater.into_card();
|
||||
if !matches!(
|
||||
answer.current_state,
|
||||
CardState::Filtered(FilteredState::Preview(_))
|
||||
) {
|
||||
card.last_review_time = Some(answer.answered_at.as_secs());
|
||||
}
|
||||
if let Some(data) = answer.custom_data.take() {
|
||||
card.custom_data = data;
|
||||
card.validate_custom_data()?;
|
||||
|
@ -346,15 +356,17 @@ impl Collection {
|
|||
}
|
||||
|
||||
if card.queue == CardQueue::Review {
|
||||
let deck = self.get_deck(card.deck_id)?;
|
||||
if let Some(card_queues) = self.state.card_queues.as_mut() {
|
||||
if let Some(deckconfig_id) = deck.and_then(|deck| deck.config_id()) {
|
||||
if let Some(load_balancer) = card_queues.load_balancer.as_mut() {
|
||||
if let Some(load_balancer) = self
|
||||
.state
|
||||
.card_queues
|
||||
.as_mut()
|
||||
.and_then(|card_queues| card_queues.load_balancer.as_mut())
|
||||
{
|
||||
if let Some(deckconfig_id) = deckconfig_id {
|
||||
load_balancer.add_card(card.id, card.note_id, deckconfig_id, card.interval)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle queue updates based on from_queue flag
|
||||
if answer.from_queue {
|
||||
|
@ -451,11 +463,14 @@ impl Collection {
|
|||
)?;
|
||||
card.set_memory_state(&fsrs, item, config.inner.historical_retention)?;
|
||||
}
|
||||
let days_elapsed = self
|
||||
.storage
|
||||
let days_elapsed = if let Some(last_review_time) = card.last_review_time {
|
||||
timing.next_day_at.elapsed_days_since(last_review_time) as u32
|
||||
} else {
|
||||
self.storage
|
||||
.time_of_last_review(card.id)?
|
||||
.map(|ts| timing.next_day_at.elapsed_days_since(ts))
|
||||
.unwrap_or_default() as u32;
|
||||
.unwrap_or_default() as u32
|
||||
};
|
||||
Some(fsrs.next_states(
|
||||
card.memory_state.map(Into::into),
|
||||
config.inner.desired_retention,
|
||||
|
|
|
@ -64,7 +64,8 @@ impl Collection {
|
|||
|
||||
pub fn empty_filtered_deck(&mut self, did: DeckId) -> Result<OpOutput<()>> {
|
||||
self.transact(Op::EmptyFilteredDeck, |col| {
|
||||
col.return_all_cards_in_filtered_deck(did)
|
||||
let deck = col.get_deck(did)?.or_not_found(did)?;
|
||||
col.return_all_cards_in_filtered_deck(&deck)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -78,8 +79,11 @@ impl Collection {
|
|||
}
|
||||
|
||||
impl Collection {
|
||||
pub(crate) fn return_all_cards_in_filtered_deck(&mut self, did: DeckId) -> Result<()> {
|
||||
let cids = self.storage.all_cards_in_single_deck(did)?;
|
||||
pub(crate) fn return_all_cards_in_filtered_deck(&mut self, deck: &Deck) -> Result<()> {
|
||||
if !deck.is_filtered() {
|
||||
return Err(FilteredDeckError::FilteredDeckRequired.into());
|
||||
}
|
||||
let cids = self.storage.all_cards_in_single_deck(deck.id)?;
|
||||
self.return_cards_to_home_deck(&cids)
|
||||
}
|
||||
|
||||
|
@ -195,7 +199,7 @@ impl Collection {
|
|||
timing,
|
||||
};
|
||||
|
||||
self.return_all_cards_in_filtered_deck(deck.id)?;
|
||||
self.return_all_cards_in_filtered_deck(deck)?;
|
||||
self.build_filtered_deck(ctx)
|
||||
}
|
||||
|
||||
|
|
|
@ -299,6 +299,33 @@ impl Collection {
|
|||
.is_ok()
|
||||
})?)
|
||||
}
|
||||
|
||||
pub fn evaluate_params_legacy(
|
||||
&mut self,
|
||||
params: &Params,
|
||||
search: &str,
|
||||
ignore_revlogs_before: TimestampMillis,
|
||||
) -> Result<ModelEvaluation> {
|
||||
let timing = self.timing_today()?;
|
||||
let mut anki_progress = self.new_progress_handler::<ComputeParamsProgress>();
|
||||
let guard = self.search_cards_into_table(search, SortMode::NoOrder)?;
|
||||
let revlogs: Vec<RevlogEntry> = guard
|
||||
.col
|
||||
.storage
|
||||
.get_revlog_entries_for_searched_cards_in_card_order()?;
|
||||
let (items, review_count) =
|
||||
fsrs_items_for_training(revlogs, timing.next_day_at, ignore_revlogs_before);
|
||||
anki_progress.state.reviews = review_count as u32;
|
||||
let fsrs = FSRS::new(Some(params))?;
|
||||
Ok(fsrs.evaluate(items, |ip| {
|
||||
anki_progress
|
||||
.update(false, |p| {
|
||||
p.total_iterations = ip.total as u32;
|
||||
p.current_iteration = ip.current as u32;
|
||||
})
|
||||
.is_ok()
|
||||
})?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
use anki_proto::scheduler::simulate_fsrs_review_request::cmrr_target::Kind;
|
||||
use anki_proto::scheduler::SimulateFsrsReviewRequest;
|
||||
use fsrs::extract_simulator_config;
|
||||
use fsrs::SimulationResult;
|
||||
use fsrs::SimulatorConfig;
|
||||
use fsrs::FSRS;
|
||||
|
||||
|
@ -16,115 +14,14 @@ pub struct ComputeRetentionProgress {
|
|||
pub total: u32,
|
||||
}
|
||||
|
||||
pub fn average_r_power_forgetting_curve(
|
||||
learn_span: usize,
|
||||
cards: &[fsrs::Card],
|
||||
offset: f32,
|
||||
decay: f32,
|
||||
) -> f32 {
|
||||
let factor = 0.9_f32.powf(1.0 / decay) - 1.0;
|
||||
let exp = decay + 1.0;
|
||||
let den_factor = factor * exp;
|
||||
|
||||
// Closure equivalent to the inner integral function
|
||||
let integral_calc = |card: &fsrs::Card| -> f32 {
|
||||
// Performs element-wise: (s / den_factor) * (1.0 + factor * t / s).powf(exp)
|
||||
let t1 = learn_span as f32 - card.last_date;
|
||||
let t2 = t1 + offset;
|
||||
(card.stability / den_factor) * (1.0 + factor * t2 / card.stability).powf(exp)
|
||||
- (card.stability / den_factor) * (1.0 + factor * t1 / card.stability).powf(exp)
|
||||
};
|
||||
|
||||
// Calculate integral difference and divide by time difference element-wise
|
||||
cards.iter().map(integral_calc).sum::<f32>() / offset
|
||||
}
|
||||
|
||||
impl Collection {
|
||||
pub fn compute_optimal_retention(&mut self, req: SimulateFsrsReviewRequest) -> Result<f32> {
|
||||
// Helper macro to wrap the closure for "CMRRTargetFn"s
|
||||
macro_rules! wrap {
|
||||
($f:expr) => {
|
||||
Some(fsrs::CMRRTargetFn(std::sync::Arc::new($f)))
|
||||
};
|
||||
}
|
||||
|
||||
let target_type = req.target.unwrap().kind;
|
||||
|
||||
let days_to_simulate = req.days_to_simulate as f32;
|
||||
|
||||
let target = match target_type {
|
||||
Some(Kind::Memorized(_)) => None,
|
||||
Some(Kind::FutureMemorized(settings)) => {
|
||||
wrap!(move |SimulationResult {
|
||||
cards,
|
||||
cost_per_day,
|
||||
..
|
||||
},
|
||||
w| {
|
||||
let total_cost = cost_per_day.iter().sum::<f32>();
|
||||
total_cost
|
||||
/ cards.iter().fold(0., |p, c| {
|
||||
c.retention_on(w, days_to_simulate + settings.days as f32) + p
|
||||
})
|
||||
})
|
||||
}
|
||||
Some(Kind::AverageFutureMemorized(settings)) => {
|
||||
wrap!(move |SimulationResult {
|
||||
cards,
|
||||
cost_per_day,
|
||||
..
|
||||
},
|
||||
w| {
|
||||
let total_cost = cost_per_day.iter().sum::<f32>();
|
||||
total_cost
|
||||
/ average_r_power_forgetting_curve(
|
||||
days_to_simulate as usize,
|
||||
cards,
|
||||
settings.days as f32,
|
||||
-w[20],
|
||||
)
|
||||
})
|
||||
}
|
||||
Some(Kind::Stability(_)) => {
|
||||
wrap!(move |SimulationResult {
|
||||
cards,
|
||||
cost_per_day,
|
||||
..
|
||||
},
|
||||
w| {
|
||||
let total_cost = cost_per_day.iter().sum::<f32>();
|
||||
total_cost
|
||||
/ cards.iter().fold(0., |p, c| {
|
||||
p + (c.retention_on(w, days_to_simulate) * c.stability)
|
||||
})
|
||||
})
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut anki_progress = self.new_progress_handler::<ComputeRetentionProgress>();
|
||||
let fsrs = FSRS::new(None)?;
|
||||
if req.days_to_simulate == 0 {
|
||||
invalid_input!("no days to simulate")
|
||||
}
|
||||
let (mut config, cards) = self.simulate_request_to_config(&req)?;
|
||||
|
||||
if let Some(Kind::Memorized(settings)) = target_type {
|
||||
let loss_aversion = settings.loss_aversion;
|
||||
|
||||
config.relearning_step_transitions[0][0] *= loss_aversion;
|
||||
config.relearning_step_transitions[1][0] *= loss_aversion;
|
||||
config.relearning_step_transitions[2][0] *= loss_aversion;
|
||||
|
||||
config.learning_step_transitions[0][0] *= loss_aversion;
|
||||
config.learning_step_transitions[1][0] *= loss_aversion;
|
||||
config.learning_step_transitions[2][0] *= loss_aversion;
|
||||
|
||||
config.state_rating_costs[0][0] *= loss_aversion;
|
||||
config.state_rating_costs[1][0] *= loss_aversion;
|
||||
config.state_rating_costs[2][0] *= loss_aversion;
|
||||
}
|
||||
|
||||
let (config, cards) = self.simulate_request_to_config(&req)?;
|
||||
Ok(fsrs
|
||||
.optimal_retention(
|
||||
&config,
|
||||
|
@ -137,7 +34,7 @@ impl Collection {
|
|||
.is_ok()
|
||||
},
|
||||
Some(cards),
|
||||
target,
|
||||
None,
|
||||
)?
|
||||
.clamp(0.7, 0.95))
|
||||
}
|
||||
|
|
|
@ -36,6 +36,11 @@ impl Card {
|
|||
let new_due = (today + days_from_today) as i32;
|
||||
let fsrs_enabled = self.memory_state.is_some();
|
||||
let new_interval = if fsrs_enabled {
|
||||
if let Some(last_review_time) = self.last_review_time {
|
||||
let elapsed_days =
|
||||
TimestampSecs(next_day_start).elapsed_days_since(last_review_time);
|
||||
elapsed_days as u32 + days_from_today
|
||||
} else {
|
||||
let due = self.original_or_current_due();
|
||||
let due_diff = if is_unix_epoch_timestamp(due) {
|
||||
let offset = (due as i64 - next_day_start) / 86_400;
|
||||
|
@ -45,6 +50,7 @@ impl Card {
|
|||
new_due - due
|
||||
};
|
||||
self.interval.saturating_add_signed(due_diff)
|
||||
}
|
||||
} else if force_reset || !matches!(self.ctype, CardType::Review | CardType::Relearn) {
|
||||
days_from_today.max(1)
|
||||
} else {
|
||||
|
|
|
@ -307,6 +307,21 @@ impl crate::services::SchedulerService for Collection {
|
|||
})
|
||||
}
|
||||
|
||||
fn evaluate_params_legacy(
|
||||
&mut self,
|
||||
input: scheduler::EvaluateParamsLegacyRequest,
|
||||
) -> Result<scheduler::EvaluateParamsResponse> {
|
||||
let ret = self.evaluate_params_legacy(
|
||||
&input.params,
|
||||
&input.search,
|
||||
input.ignore_revlogs_before_ms.into(),
|
||||
)?;
|
||||
Ok(scheduler::EvaluateParamsResponse {
|
||||
log_loss: ret.log_loss,
|
||||
rmse_bins: ret.rmse_bins,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_optimal_retention_parameters(
|
||||
&mut self,
|
||||
input: scheduler::GetOptimalRetentionParametersRequest,
|
||||
|
|
|
@ -94,6 +94,7 @@ pub enum SearchNode {
|
|||
WholeCollection,
|
||||
Regex(String),
|
||||
NoCombining(String),
|
||||
StripClozes(String),
|
||||
WordBoundary(String),
|
||||
CustomData(String),
|
||||
Preset(String),
|
||||
|
@ -358,6 +359,7 @@ fn search_node_for_text_with_argument<'a>(
|
|||
"cid" => SearchNode::CardIds(check_id_list(val, key)?.into()),
|
||||
"re" => SearchNode::Regex(unescape_quotes(val)),
|
||||
"nc" => SearchNode::NoCombining(unescape(val)?),
|
||||
"sc" => SearchNode::StripClozes(unescape(val)?),
|
||||
"w" => SearchNode::WordBoundary(unescape(val)?),
|
||||
"dupe" => parse_dupe(val)?,
|
||||
"has-cd" => SearchNode::CustomData(unescape(val)?),
|
||||
|
|
|
@ -22,6 +22,7 @@ use crate::notes::field_checksum;
|
|||
use crate::notetype::NotetypeId;
|
||||
use crate::prelude::*;
|
||||
use crate::storage::ids_to_string;
|
||||
use crate::storage::ProcessTextFlags;
|
||||
use crate::text::glob_matcher;
|
||||
use crate::text::is_glob;
|
||||
use crate::text::normalize_to_nfc;
|
||||
|
@ -134,6 +135,7 @@ impl SqlWriter<'_> {
|
|||
self.write_unqualified(
|
||||
text,
|
||||
self.col.get_config_bool(BoolKey::IgnoreAccentsInSearch),
|
||||
false,
|
||||
)?
|
||||
}
|
||||
SearchNode::SingleField { field, text, is_re } => {
|
||||
|
@ -143,7 +145,14 @@ impl SqlWriter<'_> {
|
|||
self.write_dupe(*notetype_id, &self.norm_note(text))?
|
||||
}
|
||||
SearchNode::Regex(re) => self.write_regex(&self.norm_note(re), false)?,
|
||||
SearchNode::NoCombining(text) => self.write_unqualified(&self.norm_note(text), true)?,
|
||||
SearchNode::NoCombining(text) => {
|
||||
self.write_unqualified(&self.norm_note(text), true, false)?
|
||||
}
|
||||
SearchNode::StripClozes(text) => self.write_unqualified(
|
||||
&self.norm_note(text),
|
||||
self.col.get_config_bool(BoolKey::IgnoreAccentsInSearch),
|
||||
true,
|
||||
)?,
|
||||
SearchNode::WordBoundary(text) => self.write_word_boundary(&self.norm_note(text))?,
|
||||
|
||||
// other
|
||||
|
@ -190,7 +199,12 @@ impl SqlWriter<'_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_unqualified(&mut self, text: &str, no_combining: bool) -> Result<()> {
|
||||
fn write_unqualified(
|
||||
&mut self,
|
||||
text: &str,
|
||||
no_combining: bool,
|
||||
strip_clozes: bool,
|
||||
) -> Result<()> {
|
||||
let text = to_sql(text);
|
||||
let text = if no_combining {
|
||||
without_combining(&text)
|
||||
|
@ -202,17 +216,37 @@ impl SqlWriter<'_> {
|
|||
self.args.push(text);
|
||||
let arg_idx = self.args.len();
|
||||
|
||||
let sfld_expr = if no_combining {
|
||||
"coalesce(without_combining(cast(n.sfld as text)), n.sfld)"
|
||||
let mut process_text_flags = ProcessTextFlags::empty();
|
||||
if no_combining {
|
||||
process_text_flags.insert(ProcessTextFlags::NoCombining);
|
||||
}
|
||||
if strip_clozes {
|
||||
process_text_flags.insert(ProcessTextFlags::StripClozes);
|
||||
}
|
||||
|
||||
let (sfld_expr, flds_expr) = if !process_text_flags.is_empty() {
|
||||
let bits = process_text_flags.bits();
|
||||
(
|
||||
Cow::from(format!(
|
||||
"coalesce(process_text(cast(n.sfld as text), {bits}), n.sfld)"
|
||||
)),
|
||||
Cow::from(format!("coalesce(process_text(n.flds, {bits}), n.flds)")),
|
||||
)
|
||||
} else {
|
||||
"n.sfld"
|
||||
};
|
||||
let flds_expr = if no_combining {
|
||||
"coalesce(without_combining(n.flds), n.flds)"
|
||||
} else {
|
||||
"n.flds"
|
||||
(Cow::from("n.sfld"), Cow::from("n.flds"))
|
||||
};
|
||||
|
||||
if strip_clozes {
|
||||
let cloze_notetypes_only_clause = self
|
||||
.col
|
||||
.get_all_notetypes()?
|
||||
.iter()
|
||||
.filter(|nt| nt.is_cloze())
|
||||
.map(|nt| format!("n.mid = {}", nt.id))
|
||||
.join(" or ");
|
||||
write!(self.sql, "({cloze_notetypes_only_clause}) and ").unwrap();
|
||||
}
|
||||
|
||||
if let Some(field_indicies_by_notetype) = self.included_fields_by_notetype()? {
|
||||
let field_idx_str = format!("' || ?{arg_idx} || '");
|
||||
let other_idx_str = "%".to_string();
|
||||
|
@ -803,9 +837,12 @@ impl SqlWriter<'_> {
|
|||
|
||||
fn write_regex(&mut self, word: &str, no_combining: bool) -> Result<()> {
|
||||
let flds_expr = if no_combining {
|
||||
"coalesce(without_combining(n.flds), n.flds)"
|
||||
Cow::from(format!(
|
||||
"coalesce(process_text(n.flds, {}), n.flds)",
|
||||
ProcessTextFlags::NoCombining.bits()
|
||||
))
|
||||
} else {
|
||||
"n.flds"
|
||||
Cow::from("n.flds")
|
||||
};
|
||||
let word = if no_combining {
|
||||
without_combining(word)
|
||||
|
@ -995,6 +1032,7 @@ impl SearchNode {
|
|||
SearchNode::Duplicates { .. } => RequiredTable::Notes,
|
||||
SearchNode::Regex(_) => RequiredTable::Notes,
|
||||
SearchNode::NoCombining(_) => RequiredTable::Notes,
|
||||
SearchNode::StripClozes(_) => RequiredTable::Notes,
|
||||
SearchNode::WordBoundary(_) => RequiredTable::Notes,
|
||||
SearchNode::NotetypeId(_) => RequiredTable::Notes,
|
||||
SearchNode::Notetype(_) => RequiredTable::Notes,
|
||||
|
@ -1299,6 +1337,9 @@ c.odue != 0 then c.odue else c.due end) != {days}) or (c.queue in (1,4) and
|
|||
"((c.did in (1) or c.odid in (1)))"
|
||||
);
|
||||
assert_eq!(&s(ctx, "preset:typo").0, "(false)");
|
||||
|
||||
// strip clozes
|
||||
assert_eq!(&s(ctx, "sc:abcdef").0, "((n.mid = 1581236385343) and (coalesce(process_text(cast(n.sfld as text), 2), n.sfld) like ?1 escape '\\' or coalesce(process_text(n.flds, 2), n.flds) like ?1 escape '\\'))");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -91,6 +91,7 @@ fn write_search_node(node: &SearchNode) -> String {
|
|||
WholeCollection => "deck:*".to_string(),
|
||||
Regex(s) => maybe_quote(&format!("re:{s}")),
|
||||
NoCombining(s) => maybe_quote(&format!("nc:{s}")),
|
||||
StripClozes(s) => maybe_quote(&format!("sc:{s}")),
|
||||
WordBoundary(s) => maybe_quote(&format!("w:{s}")),
|
||||
CustomData(k) => maybe_quote(&format!("has-cd:{k}")),
|
||||
Preset(s) => maybe_quote(&format!("preset:{s}")),
|
||||
|
|
|
@ -30,11 +30,14 @@ impl Collection {
|
|||
|
||||
let (average_secs, total_secs) = average_and_total_secs_strings(&revlog);
|
||||
let timing = self.timing_today()?;
|
||||
let seconds_elapsed = self
|
||||
.storage
|
||||
let seconds_elapsed = if let Some(last_review_time) = card.last_review_time {
|
||||
timing.now.elapsed_secs_since(last_review_time) as u32
|
||||
} else {
|
||||
self.storage
|
||||
.time_of_last_review(card.id)?
|
||||
.map(|ts| timing.now.elapsed_secs_since(ts))
|
||||
.unwrap_or_default() as u32;
|
||||
.unwrap_or_default() as u32
|
||||
};
|
||||
let fsrs_retrievability = card
|
||||
.memory_state
|
||||
.zip(Some(seconds_elapsed))
|
||||
|
|
|
@ -47,6 +47,12 @@ pub(crate) struct CardData {
|
|||
deserialize_with = "default_on_invalid"
|
||||
)]
|
||||
pub(crate) decay: Option<f32>,
|
||||
#[serde(
|
||||
rename = "lrt",
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "default_on_invalid"
|
||||
)]
|
||||
pub(crate) last_review_time: Option<TimestampSecs>,
|
||||
|
||||
/// A string representation of a JSON object storing optional data
|
||||
/// associated with the card, so v3 custom scheduling code can persist
|
||||
|
@ -63,6 +69,7 @@ impl CardData {
|
|||
fsrs_difficulty: card.memory_state.as_ref().map(|m| m.difficulty),
|
||||
fsrs_desired_retention: card.desired_retention,
|
||||
decay: card.decay,
|
||||
last_review_time: card.last_review_time,
|
||||
custom_data: card.custom_data.clone(),
|
||||
}
|
||||
}
|
||||
|
@ -169,6 +176,7 @@ mod test {
|
|||
fsrs_difficulty: Some(1.234567),
|
||||
fsrs_desired_retention: Some(0.987654),
|
||||
decay: Some(0.123456),
|
||||
last_review_time: None,
|
||||
custom_data: "".to_string(),
|
||||
};
|
||||
assert_eq!(
|
||||
|
|
|
@ -97,6 +97,7 @@ fn row_to_card(row: &Row) -> result::Result<Card, rusqlite::Error> {
|
|||
memory_state: data.memory_state(),
|
||||
desired_retention: data.fsrs_desired_retention,
|
||||
decay: data.decay,
|
||||
last_review_time: data.last_review_time,
|
||||
custom_data: data.custom_data,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ mod upgrades;
|
|||
|
||||
use std::fmt::Write;
|
||||
|
||||
pub(crate) use sqlite::ProcessTextFlags;
|
||||
pub(crate) use sqlite::SqliteStorage;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::hash::Hasher;
|
|||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use fnv::FnvHasher;
|
||||
use fsrs::FSRS;
|
||||
use fsrs::FSRS5_DEFAULT_DECAY;
|
||||
|
@ -24,6 +25,7 @@ use super::upgrades::SCHEMA_MAX_VERSION;
|
|||
use super::upgrades::SCHEMA_MIN_VERSION;
|
||||
use super::upgrades::SCHEMA_STARTING_VERSION;
|
||||
use super::SchemaVersion;
|
||||
use crate::cloze::strip_clozes;
|
||||
use crate::config::schema11::schema11_config_as_string;
|
||||
use crate::error::DbErrorKind;
|
||||
use crate::prelude::*;
|
||||
|
@ -31,6 +33,7 @@ use crate::scheduler::timing::local_minutes_west_for_stamp;
|
|||
use crate::scheduler::timing::v1_creation_date;
|
||||
use crate::storage::card::data::CardData;
|
||||
use crate::text::without_combining;
|
||||
use crate::text::CowMapping;
|
||||
|
||||
fn unicase_compare(s1: &str, s2: &str) -> Ordering {
|
||||
UniCase::new(s1).cmp(&UniCase::new(s2))
|
||||
|
@ -74,7 +77,7 @@ fn open_or_create_collection_db(path: &Path) -> Result<Connection> {
|
|||
add_regexp_function(&db)?;
|
||||
add_regexp_fields_function(&db)?;
|
||||
add_regexp_tags_function(&db)?;
|
||||
add_without_combining_function(&db)?;
|
||||
add_process_text_function(&db)?;
|
||||
add_fnvhash_function(&db)?;
|
||||
add_extract_original_position_function(&db)?;
|
||||
add_extract_custom_data_function(&db)?;
|
||||
|
@ -111,17 +114,28 @@ fn add_field_index_function(db: &Connection) -> rusqlite::Result<()> {
|
|||
)
|
||||
}
|
||||
|
||||
fn add_without_combining_function(db: &Connection) -> rusqlite::Result<()> {
|
||||
bitflags! {
|
||||
pub(crate) struct ProcessTextFlags: u8 {
|
||||
const NoCombining = 1;
|
||||
const StripClozes = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn add_process_text_function(db: &Connection) -> rusqlite::Result<()> {
|
||||
db.create_scalar_function(
|
||||
"without_combining",
|
||||
1,
|
||||
"process_text",
|
||||
2,
|
||||
FunctionFlags::SQLITE_DETERMINISTIC,
|
||||
|ctx| {
|
||||
let text = ctx.get_raw(0).as_str()?;
|
||||
Ok(match without_combining(text) {
|
||||
Cow::Borrowed(_) => None,
|
||||
Cow::Owned(o) => Some(o),
|
||||
})
|
||||
let mut text = Cow::from(ctx.get_raw(0).as_str()?);
|
||||
let opt = ProcessTextFlags::from_bits_truncate(ctx.get_raw(1).as_i64()? as u8);
|
||||
if opt.contains(ProcessTextFlags::StripClozes) {
|
||||
text = text.map_cow(strip_clozes);
|
||||
}
|
||||
if opt.contains(ProcessTextFlags::NoCombining) {
|
||||
text = text.map_cow(without_combining);
|
||||
}
|
||||
Ok(text.get_owned())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -314,7 +328,13 @@ fn add_extract_fsrs_retrievability(db: &Connection) -> rusqlite::Result<()> {
|
|||
let Ok(due) = ctx.get_raw(1).as_i64() else {
|
||||
return Ok(None);
|
||||
};
|
||||
let days_elapsed = if due > 365_000 {
|
||||
let days_elapsed = if let Some(last_review_time) = card_data.last_review_time {
|
||||
// Use last_review_time to calculate days_elapsed
|
||||
let Ok(next_day_at) = ctx.get_raw(4).as_i64() else {
|
||||
return Ok(None);
|
||||
};
|
||||
(next_day_at as u32).saturating_sub(last_review_time.0 as u32) / 86_400
|
||||
} else if due > 365_000 {
|
||||
// (re)learning card in seconds
|
||||
let Ok(next_day_at) = ctx.get_raw(4).as_i64() else {
|
||||
return Ok(None);
|
||||
|
@ -382,6 +402,14 @@ fn add_extract_fsrs_relative_retrievability(db: &Connection) -> rusqlite::Result
|
|||
desired_retrievability = desired_retrievability.max(0.0001);
|
||||
let decay = card_data.decay.unwrap_or(FSRS5_DEFAULT_DECAY);
|
||||
|
||||
let days_elapsed = if let Some(last_review_time) =
|
||||
card_data.last_review_time
|
||||
{
|
||||
TimestampSecs(next_day_at).elapsed_days_since(last_review_time) as u32
|
||||
} else {
|
||||
days_elapsed
|
||||
};
|
||||
|
||||
let current_retrievability = FSRS::new(None)
|
||||
.unwrap()
|
||||
.current_retrievability(state.into(), days_elapsed, decay)
|
||||
|
|
|
@ -333,6 +333,7 @@ impl From<CardEntry> for Card {
|
|||
memory_state: data.memory_state(),
|
||||
desired_retention: data.fsrs_desired_retention,
|
||||
decay: data.decay,
|
||||
last_review_time: data.last_review_time,
|
||||
custom_data: data.custom_data,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,6 @@ set -e
|
|||
|
||||
./ninja extract:uv
|
||||
|
||||
export PYENV=./out/pyenv69
|
||||
UV_PROJECT_ENVIRONMENT=$PYENV ./out/extracted/uv/uv sync --all-packages --extra qt69
|
||||
export PYENV=./out/pyenv68
|
||||
UV_PROJECT_ENVIRONMENT=$PYENV ./out/extracted/uv/uv sync --all-packages --extra qt68
|
||||
./run $*
|
|
@ -181,6 +181,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.modal {
|
||||
z-index: 1066;
|
||||
background-color: rgba($color: black, $alpha: 0.5);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
margin-inline-end: 0.75rem;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
import Row from "./Row.svelte";
|
||||
import type { HelpItem } from "./types";
|
||||
import { mdiEarth } from "./icons";
|
||||
import Icon from "./Icon.svelte";
|
||||
|
||||
export let item: HelpItem;
|
||||
</script>
|
||||
|
@ -21,6 +23,11 @@
|
|||
{/if}
|
||||
</h2>
|
||||
{#if item.help}
|
||||
{#if item.global}
|
||||
<div class="icon">
|
||||
<Icon icon={mdiEarth} />
|
||||
</div>
|
||||
{/if}
|
||||
{@html renderMarkdown(item.help)}
|
||||
{:else}
|
||||
{@html renderMarkdown(
|
||||
|
@ -54,4 +61,12 @@
|
|||
color: var(--fg-subtle);
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
fill: currentColor;
|
||||
margin-right: 0.25em;
|
||||
margin-bottom: 1.25em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -76,7 +76,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
}
|
||||
|
||||
.hide :global(.badge) {
|
||||
opacity: 0;
|
||||
display: none;
|
||||
cursor: initial;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -9,6 +9,7 @@ export type HelpItem = {
|
|||
help?: string;
|
||||
url?: string;
|
||||
sched?: HelpItemScheduler;
|
||||
global?: boolean;
|
||||
};
|
||||
|
||||
export enum HelpItemScheduler {
|
||||
|
|
|
@ -38,7 +38,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import { pageTheme } from "$lib/sveltelib/theme";
|
||||
|
||||
import { convertMathjax, unescapeSomeEntities } from "./mathjax";
|
||||
import { ChangeTimer } from "./change-timer";
|
||||
import { CooldownTimer } from "./cooldown-timer";
|
||||
|
||||
export let mathjax: string;
|
||||
export let block: boolean;
|
||||
|
@ -46,25 +46,23 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
let converted: string, title: string;
|
||||
|
||||
const debouncedMathjax = writable(mathjax);
|
||||
const debouncer = new ChangeTimer();
|
||||
$: debouncer.schedule(() => debouncedMathjax.set(mathjax), 500);
|
||||
const debouncer = new CooldownTimer(500);
|
||||
|
||||
$: {
|
||||
$: debouncer.schedule(() => {
|
||||
const cache = getCache($pageTheme.isDark, fontSize);
|
||||
const entry = cache.get($debouncedMathjax);
|
||||
const entry = cache.get(mathjax);
|
||||
if (entry) {
|
||||
[converted, title] = entry;
|
||||
} else {
|
||||
const entry = convertMathjax(
|
||||
unescapeSomeEntities($debouncedMathjax),
|
||||
unescapeSomeEntities(mathjax),
|
||||
$pageTheme.isDark,
|
||||
fontSize,
|
||||
);
|
||||
[converted, title] = entry;
|
||||
cache.set($debouncedMathjax, entry);
|
||||
}
|
||||
cache.set(mathjax, entry);
|
||||
}
|
||||
});
|
||||
$: empty = title === "MathJax";
|
||||
$: encoded = encodeURIComponent(converted);
|
||||
|
||||
|
|
31
ts/lib/editable/cooldown-timer.ts
Normal file
31
ts/lib/editable/cooldown-timer.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
export class CooldownTimer {
|
||||
private executing = false;
|
||||
private queuedAction: (() => void) | null = null;
|
||||
private delay: number;
|
||||
|
||||
constructor(delayMs: number) {
|
||||
this.delay = delayMs;
|
||||
}
|
||||
|
||||
schedule(action: () => void): void {
|
||||
if (this.executing) {
|
||||
this.queuedAction = action;
|
||||
} else {
|
||||
this.executing = true;
|
||||
action();
|
||||
setTimeout(this.#pop.bind(this), this.delay);
|
||||
}
|
||||
}
|
||||
|
||||
#pop(): void {
|
||||
this.executing = false;
|
||||
if (this.queuedAction) {
|
||||
const action = this.queuedAction;
|
||||
this.queuedAction = null;
|
||||
this.schedule(action);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ html {
|
|||
}
|
||||
|
||||
body {
|
||||
font-family: inherit;
|
||||
overflow-x: hidden;
|
||||
&:not(.isMac),
|
||||
&:not(.isMac) * {
|
||||
|
|
|
@ -95,8 +95,8 @@
|
|||
"repository": "https://github.com/TooTallNate/node-agent-base",
|
||||
"publisher": "Nathan Rajlich",
|
||||
"email": "nathan@tootallnate.net",
|
||||
"path": "node_modules/http-proxy-agent/node_modules/agent-base",
|
||||
"licenseFile": "node_modules/http-proxy-agent/node_modules/agent-base/README.md"
|
||||
"path": "node_modules/https-proxy-agent/node_modules/agent-base",
|
||||
"licenseFile": "node_modules/https-proxy-agent/node_modules/agent-base/README.md"
|
||||
},
|
||||
"asynckit@0.4.0": {
|
||||
"licenses": "MIT",
|
||||
|
|
|
@ -82,6 +82,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
title: tr.deckConfigCustomScheduling(),
|
||||
help: tr.deckConfigCustomSchedulingTooltip(),
|
||||
url: "https://faqs.ankiweb.net/the-2021-scheduler.html#add-ons-and-custom-scheduling",
|
||||
global: true,
|
||||
},
|
||||
};
|
||||
const helpSections: HelpItem[] = Object.values(settings);
|
||||
|
|
|
@ -133,14 +133,15 @@
|
|||
},
|
||||
newCardsIgnoreReviewLimit: {
|
||||
title: tr.deckConfigNewCardsIgnoreReviewLimit(),
|
||||
|
||||
help: newCardsIgnoreReviewLimitHelp,
|
||||
url: HelpPage.DeckOptions.newCardsday,
|
||||
global: true,
|
||||
},
|
||||
applyAllParentLimits: {
|
||||
title: tr.deckConfigApplyAllParentLimits(),
|
||||
help: applyAllParentLimitsHelp,
|
||||
url: HelpPage.DeckOptions.newCardsday,
|
||||
global: true,
|
||||
},
|
||||
};
|
||||
const helpSections: HelpItem[] = Object.values(settings);
|
||||
|
|
|
@ -20,27 +20,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
</script>
|
||||
|
||||
<Item>
|
||||
<div class="container">
|
||||
<div class="easy-days-settings">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="header min-col">
|
||||
<span>{tr.deckConfigEasyDaysMinimum()}</span>
|
||||
</th>
|
||||
<th class="header text-center">
|
||||
<span>{tr.deckConfigEasyDaysReduced()}</span>
|
||||
</th>
|
||||
<th class="header normal-col">
|
||||
<span>{tr.deckConfigEasyDaysNormal()}</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<span></span>
|
||||
<span class="header min-col">{tr.deckConfigEasyDaysMinimum()}</span>
|
||||
<span class="header">{tr.deckConfigEasyDaysReduced()}</span>
|
||||
<span class="header normal-col">{tr.deckConfigEasyDaysNormal()}</span>
|
||||
|
||||
{#each easyDays as day, index}
|
||||
<tr>
|
||||
<td class="day">{day}</td>
|
||||
<td colspan="3">
|
||||
<span class="day">{day}</span>
|
||||
<div class="input-container">
|
||||
<input
|
||||
type="range"
|
||||
bind:value={values[index]}
|
||||
|
@ -49,25 +38,47 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
min={0.0}
|
||||
list="easy_day_steplist"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</div>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</Item>
|
||||
|
||||
<style>
|
||||
.easy-days-settings table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
<style lang="scss">
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.easy-days-settings th,
|
||||
.easy-days-settings td {
|
||||
padding: 8px;
|
||||
.easy-days-settings {
|
||||
width: 100%;
|
||||
max-width: 1000px;
|
||||
border-collapse: collapse;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr 1fr 1fr;
|
||||
|
||||
border-collapse: collapse;
|
||||
& > * {
|
||||
padding: 8px 16px;
|
||||
border-bottom: var(--border) solid 1px;
|
||||
}
|
||||
}
|
||||
.input-container {
|
||||
grid-column: 2 / span 3;
|
||||
}
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.min-col {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
&.normal-col {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
.header {
|
||||
word-wrap: break-word;
|
||||
font-size: smaller;
|
||||
|
@ -80,12 +91,4 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
word-wrap: break-word;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.min-col {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.normal-col {
|
||||
text-align: end;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -7,14 +7,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
ComputeRetentionProgress,
|
||||
type ComputeParamsProgress,
|
||||
} from "@generated/anki/collection_pb";
|
||||
import {
|
||||
SimulateFsrsReviewRequest,
|
||||
SimulateFsrsReviewRequest_CMRRTarget,
|
||||
SimulateFsrsReviewRequest_CMRRTarget_Memorized,
|
||||
} from "@generated/anki/scheduler_pb";
|
||||
import { SimulateFsrsReviewRequest } from "@generated/anki/scheduler_pb";
|
||||
import {
|
||||
computeFsrsParams,
|
||||
evaluateParams,
|
||||
evaluateParamsLegacy,
|
||||
getRetentionWorkload,
|
||||
setWantsAbort,
|
||||
} from "@generated/backend";
|
||||
|
@ -99,14 +95,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
newCardsIgnoreReviewLimit: $newCardsIgnoreReviewLimit,
|
||||
easyDaysPercentages: $config.easyDaysPercentages,
|
||||
reviewOrder: $config.reviewOrder,
|
||||
target: new SimulateFsrsReviewRequest_CMRRTarget({
|
||||
kind: {
|
||||
case: "memorized",
|
||||
value: new SimulateFsrsReviewRequest_CMRRTarget_Memorized({
|
||||
lossAversion: 1.6,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const DESIRED_RETENTION_LOW_THRESHOLD = 0.8;
|
||||
|
@ -256,10 +244,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
const search = $config.paramSearch
|
||||
? $config.paramSearch
|
||||
: defaultparamSearch;
|
||||
const resp = await evaluateParams({
|
||||
const resp = await evaluateParamsLegacy({
|
||||
search,
|
||||
ignoreRevlogsBeforeMs: getIgnoreRevlogsBeforeMs(),
|
||||
numOfRelearningSteps: $config.relearnSteps.length,
|
||||
params: fsrsParams($config),
|
||||
});
|
||||
if (computeParamsProgress) {
|
||||
computeParamsProgress.current = computeParamsProgress.total;
|
||||
|
@ -373,8 +361,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
{tr.deckConfigOptimizeButton()}
|
||||
{/if}
|
||||
</button>
|
||||
{#if false}
|
||||
<!-- Can be re-enabled by some method in the future -->
|
||||
{#if state.legacyEvaluate}
|
||||
<button
|
||||
class="btn {checkingParams ? 'btn-warning' : 'btn-primary'}"
|
||||
disabled={!checkingParams && computing}
|
||||
|
|
|
@ -35,6 +35,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
title: "FSRS",
|
||||
help: tr.deckConfigFsrsTooltip(),
|
||||
url: HelpPage.DeckOptions.fsrs,
|
||||
global: true,
|
||||
},
|
||||
desiredRetention: {
|
||||
title: tr.deckConfigDesiredRetention(),
|
||||
|
@ -56,6 +57,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
title: tr.deckConfigRescheduleCardsOnChange(),
|
||||
help: tr.deckConfigRescheduleCardsOnChangeTooltip(),
|
||||
sched: HelpItemScheduler.FSRS,
|
||||
global: true,
|
||||
},
|
||||
computeOptimalRetention: {
|
||||
title: tr.deckConfigComputeOptimalRetention(),
|
||||
|
@ -65,10 +67,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
healthCheck: {
|
||||
title: tr.deckConfigHealthCheck(),
|
||||
help:
|
||||
tr.deckConfigAffectsEntireCollection() +
|
||||
"\n\n" +
|
||||
tr.deckConfigHealthCheckTooltip1() +
|
||||
"\n\n" +
|
||||
tr.deckConfigHealthCheckTooltip2(),
|
||||
sched: HelpItemScheduler.FSRS,
|
||||
global: true,
|
||||
},
|
||||
};
|
||||
const helpSections: HelpItem[] = Object.values(settings);
|
||||
|
|
|
@ -18,30 +18,21 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import { renderSimulationChart } from "../graphs/simulator";
|
||||
import { computeOptimalRetention, simulateFsrsReview } from "@generated/backend";
|
||||
import { runWithBackendProgress } from "@tslib/progress";
|
||||
import {
|
||||
SimulateFsrsReviewRequest_CMRRTarget_AverageFutureMemorized,
|
||||
SimulateFsrsReviewRequest_CMRRTarget_FutureMemorized,
|
||||
SimulateFsrsReviewRequest_CMRRTarget_Memorized,
|
||||
SimulateFsrsReviewRequest_CMRRTarget_Stability,
|
||||
type ComputeOptimalRetentionResponse,
|
||||
type SimulateFsrsReviewRequest,
|
||||
type SimulateFsrsReviewResponse,
|
||||
import type {
|
||||
ComputeOptimalRetentionResponse,
|
||||
SimulateFsrsReviewRequest,
|
||||
SimulateFsrsReviewResponse,
|
||||
} from "@generated/anki/scheduler_pb";
|
||||
import type { DeckOptionsState } from "./lib";
|
||||
import SwitchRow from "$lib/components/SwitchRow.svelte";
|
||||
import GlobalLabel from "./GlobalLabel.svelte";
|
||||
import SpinBoxFloatRow from "./SpinBoxFloatRow.svelte";
|
||||
import {
|
||||
DEFAULT_CMRR_TARGET,
|
||||
CMRRTargetChoices,
|
||||
reviewOrderChoices,
|
||||
} from "./choices";
|
||||
import { reviewOrderChoices } from "./choices";
|
||||
import EnumSelectorRow from "$lib/components/EnumSelectorRow.svelte";
|
||||
import { DeckConfig_Config_LeechAction } from "@generated/anki/deck_config_pb";
|
||||
import EasyDaysInput from "./EasyDaysInput.svelte";
|
||||
import Warning from "./Warning.svelte";
|
||||
import type { ComputeRetentionProgress } from "@generated/anki/collection_pb";
|
||||
import Item from "$lib/components/Item.svelte";
|
||||
import Modal from "bootstrap/js/dist/modal";
|
||||
|
||||
export let state: DeckOptionsState;
|
||||
|
@ -50,45 +41,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
export let openHelpModal: (key: string) => void;
|
||||
export let onPresetChange: () => void;
|
||||
|
||||
let cmrrTargetType = DEFAULT_CMRR_TARGET;
|
||||
// All added types must be updated in the proceeding switch statement.
|
||||
let lastCmrrTargetType = cmrrTargetType;
|
||||
$: if (simulateFsrsRequest?.target && cmrrTargetType !== lastCmrrTargetType) {
|
||||
switch (cmrrTargetType) {
|
||||
case "memorized":
|
||||
simulateFsrsRequest.target.kind = {
|
||||
case: "memorized",
|
||||
value: new SimulateFsrsReviewRequest_CMRRTarget_Memorized({
|
||||
lossAversion: 1.6,
|
||||
}),
|
||||
};
|
||||
break;
|
||||
case "stability":
|
||||
simulateFsrsRequest.target.kind = {
|
||||
case: "stability",
|
||||
value: new SimulateFsrsReviewRequest_CMRRTarget_Stability({}),
|
||||
};
|
||||
break;
|
||||
case "futureMemorized":
|
||||
simulateFsrsRequest.target.kind = {
|
||||
case: "futureMemorized",
|
||||
value: new SimulateFsrsReviewRequest_CMRRTarget_FutureMemorized({
|
||||
days: 365,
|
||||
}),
|
||||
};
|
||||
break;
|
||||
case "averageFutureMemorized":
|
||||
simulateFsrsRequest.target.kind = {
|
||||
case: "averageFutureMemorized",
|
||||
value: new SimulateFsrsReviewRequest_CMRRTarget_AverageFutureMemorized(
|
||||
{ days: 365 },
|
||||
),
|
||||
};
|
||||
break;
|
||||
}
|
||||
lastCmrrTargetType = cmrrTargetType;
|
||||
}
|
||||
|
||||
const config = state.currentConfig;
|
||||
let simulateSubgraph: SimulateSubgraph = SimulateSubgraph.count;
|
||||
let tableData: TableDatum[] = [];
|
||||
|
@ -344,7 +296,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
min={0}
|
||||
max={9999}
|
||||
>
|
||||
<SettingTitle on:click={() => openHelpModal("simulateFsrsReview")}>
|
||||
<SettingTitle on:click={() => openHelpModal("newLimit")}>
|
||||
{tr.schedulingNewCardsday()}
|
||||
</SettingTitle>
|
||||
</SpinBoxRow>
|
||||
|
@ -355,7 +307,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
min={0}
|
||||
max={9999}
|
||||
>
|
||||
<SettingTitle on:click={() => openHelpModal("simulateFsrsReview")}>
|
||||
<SettingTitle on:click={() => openHelpModal("reviewLimit")}>
|
||||
{tr.schedulingMaximumReviewsday()}
|
||||
</SettingTitle>
|
||||
</SpinBoxRow>
|
||||
|
@ -375,9 +327,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
min={1}
|
||||
max={36500}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() => openHelpModal("simulateFsrsReview")}
|
||||
>
|
||||
<SettingTitle on:click={() => openHelpModal("maximumInterval")}>
|
||||
{tr.schedulingMaximumInterval()}
|
||||
</SettingTitle>
|
||||
</SpinBoxRow>
|
||||
|
@ -387,9 +337,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
defaultValue={$config.reviewOrder}
|
||||
choices={reviewOrderChoices($fsrs)}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() => openHelpModal("simulateFsrsReview")}
|
||||
>
|
||||
<SettingTitle on:click={() => openHelpModal("reviewSortOrder")}>
|
||||
{tr.deckConfigReviewSortOrder()}
|
||||
</SettingTitle>
|
||||
</EnumSelectorRow>
|
||||
|
@ -399,7 +347,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
defaultValue={$newCardsIgnoreReviewLimit}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() => openHelpModal("simulateFsrsReview")}
|
||||
on:click={() => openHelpModal("newCardsIgnoreReviewLimit")}
|
||||
>
|
||||
<GlobalLabel
|
||||
title={tr.deckConfigNewCardsIgnoreReviewLimit()}
|
||||
|
@ -420,9 +368,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
defaultValue={$config.leechAction ==
|
||||
DeckConfig_Config_LeechAction.SUSPEND}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() => openHelpModal("simulateFsrsReview")}
|
||||
>
|
||||
<SettingTitle on:click={() => openHelpModal("leechAction")}>
|
||||
{tr.deckConfigSuspendLeeches()}
|
||||
</SettingTitle>
|
||||
</SwitchRow>
|
||||
|
@ -435,7 +381,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
max={9999}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() => openHelpModal("simulateFsrsReview")}
|
||||
on:click={() => openHelpModal("leechThreshold")}
|
||||
>
|
||||
{tr.schedulingLeechThreshold()}
|
||||
</SettingTitle>
|
||||
|
@ -443,10 +389,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
{/if}
|
||||
</details>
|
||||
|
||||
<div style="display:none;">
|
||||
<details>
|
||||
<summary>{tr.deckConfigComputeOptimalRetention()}</summary>
|
||||
<button
|
||||
class="btn {computingRetention ? 'btn-warning' : 'btn-primary'}"
|
||||
class="btn {computingRetention
|
||||
? 'btn-warning'
|
||||
: 'btn-primary'}"
|
||||
disabled={!computingRetention && computing}
|
||||
on:click={() => computeRetention()}
|
||||
>
|
||||
|
@ -470,45 +419,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
{#if computingRetention}
|
||||
<div>{computeRetentionProgressString}</div>
|
||||
{/if}
|
||||
|
||||
<Item>
|
||||
<EnumSelectorRow
|
||||
choices={CMRRTargetChoices()}
|
||||
bind:value={cmrrTargetType}
|
||||
defaultValue={DEFAULT_CMRR_TARGET}
|
||||
>
|
||||
<SettingTitle>
|
||||
{"Target: "}
|
||||
</SettingTitle>
|
||||
</EnumSelectorRow>
|
||||
</Item>
|
||||
|
||||
{#if simulateFsrsRequest.target?.kind.case === "memorized"}
|
||||
<SpinBoxFloatRow
|
||||
bind:value={
|
||||
simulateFsrsRequest.target.kind.value.lossAversion
|
||||
}
|
||||
defaultValue={1.6}
|
||||
>
|
||||
<SettingTitle>
|
||||
{"Fail Cost Multiplier: "}
|
||||
</SettingTitle>
|
||||
</SpinBoxFloatRow>
|
||||
{/if}
|
||||
|
||||
{#if simulateFsrsRequest.target?.kind.case === "futureMemorized" || simulateFsrsRequest.target?.kind.case === "averageFutureMemorized"}
|
||||
<SpinBoxFloatRow
|
||||
bind:value={simulateFsrsRequest.target.kind.value.days}
|
||||
defaultValue={365}
|
||||
step={1}
|
||||
>
|
||||
<SettingTitle>
|
||||
{"Days after simulation end: "}
|
||||
</SettingTitle>
|
||||
</SpinBoxFloatRow>
|
||||
{/if}
|
||||
</details>
|
||||
|
||||
</div>
|
||||
<button
|
||||
class="btn {computing ? 'btn-warning' : 'btn-primary'}"
|
||||
disabled={computing}
|
||||
|
@ -529,10 +441,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
class="btn {computing ? 'btn-warning' : 'btn-primary'}"
|
||||
disabled={computing}
|
||||
on:click={() => {
|
||||
if (confirm(tr.deckConfigSaveOptionsToPresetConfirm())) {
|
||||
$config.newPerDay = simulateFsrsRequest.newLimit;
|
||||
$config.reviewsPerDay = simulateFsrsRequest.reviewLimit;
|
||||
$config.maximumReviewInterval = simulateFsrsRequest.maxInterval;
|
||||
$config.desiredRetention = simulateFsrsRequest.desiredRetention;
|
||||
$config.maximumReviewInterval =
|
||||
simulateFsrsRequest.maxInterval;
|
||||
$config.desiredRetention =
|
||||
simulateFsrsRequest.desiredRetention;
|
||||
$newCardsIgnoreReviewLimit =
|
||||
simulateFsrsRequest.newCardsIgnoreReviewLimit;
|
||||
$config.reviewOrder = simulateFsrsRequest.reviewOrder;
|
||||
|
@ -542,6 +457,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
$config.leechThreshold = leechThreshold;
|
||||
$config.easyDaysPercentages = [...easyDayPercentages];
|
||||
onPresetChange();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{tr.deckConfigSaveOptionsToPreset()}
|
||||
|
|
|
@ -199,29 +199,6 @@ export function questionActionChoices(): Choice<DeckConfig_Config_QuestionAction
|
|||
];
|
||||
}
|
||||
|
||||
export const DEFAULT_CMRR_TARGET = "memorized";
|
||||
|
||||
export function CMRRTargetChoices(): Choice<string>[] {
|
||||
return [
|
||||
{
|
||||
label: "Memorized (Default)",
|
||||
value: "memorized",
|
||||
},
|
||||
{
|
||||
label: "Stability (Experimental)",
|
||||
value: "stability",
|
||||
},
|
||||
{
|
||||
label: "Post Abandon Memorized (Experimental)",
|
||||
value: "futureMemorized",
|
||||
},
|
||||
{
|
||||
label: "Average Post Abandon Memorized (Experimental)",
|
||||
value: "averageFutureMemorized",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function difficultyOrders(fsrs: boolean): Choice<DeckConfig_Config_ReviewCardOrder>[] {
|
||||
const order = [
|
||||
{
|
||||
|
|
|
@ -63,6 +63,7 @@ export class DeckOptionsState {
|
|||
readonly fsrs: Writable<boolean>;
|
||||
readonly fsrsReschedule: Writable<boolean> = writable(false);
|
||||
readonly fsrsHealthCheck: Writable<boolean>;
|
||||
readonly legacyEvaluate: boolean;
|
||||
readonly daysSinceLastOptimization: Writable<number>;
|
||||
readonly currentPresetName: Writable<string>;
|
||||
/** Used to detect if there are any pending changes */
|
||||
|
@ -105,6 +106,7 @@ export class DeckOptionsState {
|
|||
this.applyAllParentLimits = writable(data.applyAllParentLimits);
|
||||
this.fsrs = writable(data.fsrs);
|
||||
this.fsrsHealthCheck = writable(data.fsrsHealthCheck);
|
||||
this.legacyEvaluate = data.fsrsLegacyEvaluate;
|
||||
this.daysSinceLastOptimization = writable(data.daysSinceLastFsrsOptimize);
|
||||
|
||||
// decrement the use count of the starting item, as we'll apply +1 to currently
|
||||
|
|
|
@ -10,5 +10,6 @@ $btn-disabled-opacity: 0.4;
|
|||
|
||||
html,
|
||||
body {
|
||||
font-family: var(--bs-font-sans-serif);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
-->
|
||||
<script lang="ts">
|
||||
import { bridgeCommand } from "@tslib/bridgecommand";
|
||||
import type { SvelteComponent } from "svelte";
|
||||
import type { Component } from "svelte";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import { pageTheme } from "$lib/sveltelib/theme";
|
||||
|
@ -18,9 +18,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
const search = writable(initialSearch);
|
||||
const days = writable(initialDays);
|
||||
|
||||
export let graphs: (typeof SvelteComponent<any>)[];
|
||||
export let graphs: Component<any>[];
|
||||
/** See RangeBox */
|
||||
export let controller: typeof SvelteComponent<any> | null = RangeBox;
|
||||
export let controller: Component<any> | null = RangeBox;
|
||||
|
||||
function browserSearch(event: CustomEvent) {
|
||||
bridgeCommand(`browserSearch: ${$search} ${event.detail.query}`);
|
||||
|
|
|
@ -9,18 +9,18 @@ import "./graphs-base.scss";
|
|||
|
||||
import { ModuleName, setupI18n } from "@tslib/i18n";
|
||||
import { checkNightMode } from "@tslib/nightmode";
|
||||
import type { SvelteComponent } from "svelte";
|
||||
import type { Component } from "svelte";
|
||||
|
||||
import GraphsPage from "./GraphsPage.svelte";
|
||||
|
||||
const i18n = setupI18n({ modules: [ModuleName.STATISTICS, ModuleName.SCHEDULING] });
|
||||
|
||||
export async function setupGraphs(
|
||||
graphs: typeof SvelteComponent<any>[],
|
||||
graphs: Component<any>[],
|
||||
{
|
||||
search = "deck:current",
|
||||
days = 365,
|
||||
controller = null satisfies typeof SvelteComponent<any> | null,
|
||||
controller = null satisfies Component<any> | null,
|
||||
} = {},
|
||||
): Promise<GraphsPage> {
|
||||
checkNightMode();
|
||||
|
|
|
@ -17,12 +17,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
import { dupeResolutionChoices, matchScopeChoices } from "./choices";
|
||||
import type { ImportCsvState } from "./lib";
|
||||
import Warning from "../deck-options/Warning.svelte";
|
||||
|
||||
export let state: ImportCsvState;
|
||||
|
||||
const metadata = state.metadata;
|
||||
const globalNotetype = state.globalNotetype;
|
||||
const deckId = state.deckId;
|
||||
const deckName = state.newDeckName;
|
||||
|
||||
const settings = {
|
||||
notetype: {
|
||||
|
@ -64,6 +66,22 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
modal.show();
|
||||
carousel.to(index);
|
||||
}
|
||||
|
||||
const choices = state.deckNameIds.map(({ id, name }) => {
|
||||
return { label: name, value: id };
|
||||
});
|
||||
|
||||
if (deckName) {
|
||||
choices.push({
|
||||
label: deckName,
|
||||
value: 0n,
|
||||
});
|
||||
}
|
||||
|
||||
$: newDeckCreationNotice =
|
||||
deckName && $deckId === 0n
|
||||
? tr.importingNewDeckWillBeCreated({ name: deckName })
|
||||
: "";
|
||||
</script>
|
||||
|
||||
<TitledContainer title={tr.importingImportOptions()}>
|
||||
|
@ -95,13 +113,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
</EnumSelectorRow>
|
||||
{/if}
|
||||
|
||||
{#if $deckId !== null}
|
||||
{#if deckName || $deckId}
|
||||
<EnumSelectorRow
|
||||
bind:value={$deckId}
|
||||
defaultValue={state.defaultDeckId}
|
||||
choices={state.deckNameIds.map(({ id, name }) => {
|
||||
return { label: name, value: id };
|
||||
})}
|
||||
{choices}
|
||||
>
|
||||
<SettingTitle
|
||||
on:click={() => openHelpModal(Object.keys(settings).indexOf("deck"))}
|
||||
|
@ -111,6 +127,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
</EnumSelectorRow>
|
||||
{/if}
|
||||
|
||||
<Warning warning={newDeckCreationNotice} className="alert-info" />
|
||||
|
||||
<EnumSelectorRow
|
||||
bind:value={$metadata.dupeResolution}
|
||||
defaultValue={0}
|
||||
|
|
|
@ -22,8 +22,12 @@ export function getGlobalNotetype(meta: CsvMetadata): CsvMetadata_MappedNotetype
|
|||
return meta.notetype.case === "globalNotetype" ? meta.notetype.value : null;
|
||||
}
|
||||
|
||||
export function getDeckId(meta: CsvMetadata): bigint | null {
|
||||
return meta.deck.case === "deckId" ? meta.deck.value : null;
|
||||
export function getDeckId(meta: CsvMetadata): bigint {
|
||||
return meta.deck.case === "deckId" ? meta.deck.value : 0n;
|
||||
}
|
||||
|
||||
export function getDeckName(meta: CsvMetadata): string | null {
|
||||
return meta.deck.case === "deckName" ? meta.deck.value : null;
|
||||
}
|
||||
|
||||
export class ImportCsvState {
|
||||
|
@ -35,6 +39,7 @@ export class ImportCsvState {
|
|||
readonly defaultIsHtml: boolean;
|
||||
readonly defaultNotetypeId: bigint | null;
|
||||
readonly defaultDeckId: bigint | null;
|
||||
readonly newDeckName: string | null;
|
||||
|
||||
readonly metadata: Writable<CsvMetadata>;
|
||||
readonly globalNotetype: Writable<CsvMetadata_MappedNotetype | null>;
|
||||
|
@ -83,6 +88,7 @@ export class ImportCsvState {
|
|||
this.defaultIsHtml = metadata.isHtml;
|
||||
this.defaultNotetypeId = this.lastGlobalNotetype?.id || null;
|
||||
this.defaultDeckId = this.lastDeckId;
|
||||
this.newDeckName = getDeckName(metadata);
|
||||
}
|
||||
|
||||
doImport(): Promise<ImportResponse> {
|
||||
|
@ -104,7 +110,7 @@ export class ImportCsvState {
|
|||
path: this.path,
|
||||
delimiter: changed.delimiter,
|
||||
notetypeId: getGlobalNotetype(changed)?.id,
|
||||
deckId: getDeckId(changed) ?? undefined,
|
||||
deckId: getDeckId(changed) || undefined,
|
||||
isHtml: changed.isHtml,
|
||||
});
|
||||
// carry over tags
|
||||
|
@ -157,7 +163,13 @@ export class ImportCsvState {
|
|||
this.lastDeckId = deckId;
|
||||
if (deckId !== null) {
|
||||
this.metadata.update((metadata) => {
|
||||
if (deckId !== 0n) {
|
||||
metadata.deck.case = "deckId";
|
||||
metadata.deck.value = deckId;
|
||||
} else {
|
||||
metadata.deck.case = "deckName";
|
||||
metadata.deck.value = this.newDeckName!;
|
||||
}
|
||||
return metadata;
|
||||
});
|
||||
}
|
||||
|
|
262
uv.lock
262
uv.lock
|
@ -11,7 +11,7 @@ conflicts = [[
|
|||
{ package = "aqt", extra = "qt" },
|
||||
{ package = "aqt", extra = "qt66" },
|
||||
{ package = "aqt", extra = "qt67" },
|
||||
{ package = "aqt", extra = "qt69" },
|
||||
{ package = "aqt", extra = "qt68" },
|
||||
]]
|
||||
|
||||
[manifest]
|
||||
|
@ -52,7 +52,7 @@ name = "anki"
|
|||
source = { editable = "pylib" }
|
||||
dependencies = [
|
||||
{ name = "decorator" },
|
||||
{ name = "distro", marker = "(sys_platform != 'darwin' and sys_platform != 'win32') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "distro", marker = "(sys_platform != 'darwin' and sys_platform != 'win32') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (sys_platform == 'darwin' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (sys_platform == 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "markdown" },
|
||||
{ name = "orjson" },
|
||||
{ name = "protobuf" },
|
||||
|
@ -88,9 +88,9 @@ source = { virtual = "." }
|
|||
|
||||
[package.optional-dependencies]
|
||||
sphinx = [
|
||||
{ name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx-autoapi" },
|
||||
{ name = "sphinx-rtd-theme" },
|
||||
]
|
||||
|
@ -157,22 +157,22 @@ wheels = [
|
|||
name = "aqt"
|
||||
source = { editable = "qt" }
|
||||
dependencies = [
|
||||
{ name = "anki-mac-helper", marker = "sys_platform == 'darwin' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "anki-mac-helper", marker = "sys_platform == 'darwin' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "beautifulsoup4" },
|
||||
{ name = "flask", extra = ["async"] },
|
||||
{ name = "flask-cors" },
|
||||
{ name = "jsonschema" },
|
||||
{ name = "pip-system-certs", version = "4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pip-system-certs", version = "5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6", version = "6.6.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6", version = "6.7.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6", version = "6.8.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6", version = "6.9.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt69' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra != 'extra-3-aqt-qt67')" },
|
||||
{ name = "pyqt6-webengine", version = "6.6.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-webengine", version = "6.7.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-webengine", version = "6.8.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-webengine", version = "6.9.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt69' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra != 'extra-3-aqt-qt67')" },
|
||||
{ name = "pywin32", marker = "sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pip-system-certs", version = "4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pip-system-certs", version = "5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6", version = "6.6.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6", version = "6.7.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6", version = "6.8.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6", version = "6.9.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt66' and extra != 'extra-3-aqt-qt67' and extra != 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-webengine", version = "6.6.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-webengine", version = "6.7.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-webengine", version = "6.8.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-webengine", version = "6.9.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt66' and extra != 'extra-3-aqt-qt67' and extra != 'extra-3-aqt-qt68')" },
|
||||
{ name = "pywin32", marker = "sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "requests" },
|
||||
{ name = "send2trash" },
|
||||
{ name = "waitress" },
|
||||
|
@ -180,14 +180,14 @@ dependencies = [
|
|||
|
||||
[package.optional-dependencies]
|
||||
audio = [
|
||||
{ name = "anki-audio", marker = "sys_platform == 'darwin' or sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "anki-audio", marker = "sys_platform == 'darwin' or sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
qt = [
|
||||
{ name = "pyqt6", version = "6.8.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-qt6", version = "6.8.1", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6", version = "6.9.1", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-qt6", version = "6.9.1", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine", version = "6.8.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.8.1", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine", version = "6.9.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.9.1", source = { registry = "https://pypi.org/simple" } },
|
||||
]
|
||||
qt66 = [
|
||||
{ name = "pyqt6", version = "6.6.1", source = { registry = "https://pypi.org/simple" } },
|
||||
|
@ -203,12 +203,12 @@ qt67 = [
|
|||
{ name = "pyqt6-webengine", version = "6.7.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.7.3", source = { registry = "https://pypi.org/simple" } },
|
||||
]
|
||||
qt69 = [
|
||||
{ name = "pyqt6", version = "6.9.1", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-qt6", version = "6.9.1", source = { registry = "https://pypi.org/simple" } },
|
||||
qt68 = [
|
||||
{ name = "pyqt6", version = "6.8.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-qt6", version = "6.8.1", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine", version = "6.9.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.9.1", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine", version = "6.8.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.8.1", source = { registry = "https://pypi.org/simple" } },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
|
@ -221,33 +221,33 @@ requires-dist = [
|
|||
{ name = "jsonschema" },
|
||||
{ name = "pip-system-certs", specifier = "!=5.1" },
|
||||
{ name = "pyqt6", specifier = ">=6.2" },
|
||||
{ name = "pyqt6", marker = "extra == 'qt'", specifier = "==6.8.0" },
|
||||
{ name = "pyqt6", marker = "extra == 'qt'", specifier = "==6.9.1" },
|
||||
{ name = "pyqt6", marker = "extra == 'qt66'", specifier = "==6.6.1" },
|
||||
{ name = "pyqt6", marker = "extra == 'qt67'", specifier = "==6.7.1" },
|
||||
{ name = "pyqt6", marker = "extra == 'qt69'", specifier = "==6.9.1" },
|
||||
{ name = "pyqt6-qt6", marker = "extra == 'qt'", specifier = "==6.8.1" },
|
||||
{ name = "pyqt6", marker = "extra == 'qt68'", specifier = "==6.8.0" },
|
||||
{ name = "pyqt6-qt6", marker = "extra == 'qt'", specifier = "==6.9.1" },
|
||||
{ name = "pyqt6-qt6", marker = "extra == 'qt66'", specifier = "==6.6.2" },
|
||||
{ name = "pyqt6-qt6", marker = "extra == 'qt67'", specifier = "==6.7.3" },
|
||||
{ name = "pyqt6-qt6", marker = "extra == 'qt69'", specifier = "==6.9.1" },
|
||||
{ name = "pyqt6-qt6", marker = "extra == 'qt68'", specifier = "==6.8.1" },
|
||||
{ name = "pyqt6-sip", marker = "extra == 'qt'", specifier = "==13.10.2" },
|
||||
{ name = "pyqt6-sip", marker = "extra == 'qt66'", specifier = "==13.6.0" },
|
||||
{ name = "pyqt6-sip", marker = "extra == 'qt67'", specifier = "==13.10.2" },
|
||||
{ name = "pyqt6-sip", marker = "extra == 'qt69'", specifier = "==13.10.2" },
|
||||
{ name = "pyqt6-sip", marker = "extra == 'qt68'", specifier = "==13.10.2" },
|
||||
{ name = "pyqt6-webengine", specifier = ">=6.2" },
|
||||
{ name = "pyqt6-webengine", marker = "extra == 'qt'", specifier = "==6.8.0" },
|
||||
{ name = "pyqt6-webengine", marker = "extra == 'qt'", specifier = "==6.9.0" },
|
||||
{ name = "pyqt6-webengine", marker = "extra == 'qt66'", specifier = "==6.6.0" },
|
||||
{ name = "pyqt6-webengine", marker = "extra == 'qt67'", specifier = "==6.7.0" },
|
||||
{ name = "pyqt6-webengine", marker = "extra == 'qt69'", specifier = "==6.9.0" },
|
||||
{ name = "pyqt6-webengine-qt6", marker = "extra == 'qt'", specifier = "==6.8.1" },
|
||||
{ name = "pyqt6-webengine", marker = "extra == 'qt68'", specifier = "==6.8.0" },
|
||||
{ name = "pyqt6-webengine-qt6", marker = "extra == 'qt'", specifier = "==6.9.1" },
|
||||
{ name = "pyqt6-webengine-qt6", marker = "extra == 'qt66'", specifier = "==6.6.2" },
|
||||
{ name = "pyqt6-webengine-qt6", marker = "extra == 'qt67'", specifier = "==6.7.3" },
|
||||
{ name = "pyqt6-webengine-qt6", marker = "extra == 'qt69'", specifier = "==6.9.1" },
|
||||
{ name = "pyqt6-webengine-qt6", marker = "extra == 'qt68'", specifier = "==6.8.1" },
|
||||
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
||||
{ name = "requests" },
|
||||
{ name = "send2trash" },
|
||||
{ name = "waitress", specifier = ">=2.0.0" },
|
||||
]
|
||||
provides-extras = ["audio", "qt", "qt66", "qt67", "qt69"]
|
||||
provides-extras = ["audio", "qt", "qt66", "qt67", "qt68"]
|
||||
|
||||
[[package]]
|
||||
name = "asgiref"
|
||||
|
@ -266,7 +266,7 @@ name = "astroid"
|
|||
version = "3.3.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/00/c2/9b2de9ed027f9fe5734a6c0c0a601289d796b3caaf1e372e23fa88a73047/astroid-3.3.10.tar.gz", hash = "sha256:c332157953060c6deb9caa57303ae0d20b0fbdb2e59b4a4f2a6ba49d0a7961ce", size = 398941, upload-time = "2025-05-10T13:33:10.405Z" }
|
||||
wheels = [
|
||||
|
@ -404,7 +404,7 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "(python_full_version < '3.10' and sys_platform == 'win32') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "colorama", marker = "(python_full_version < '3.10' and sys_platform == 'win32') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" }
|
||||
wheels = [
|
||||
|
@ -421,7 +421,7 @@ resolution-markers = [
|
|||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "(python_full_version >= '3.10' and sys_platform == 'win32') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "colorama", marker = "(python_full_version >= '3.10' and sys_platform == 'win32') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (python_full_version < '3.10' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" }
|
||||
wheels = [
|
||||
|
@ -469,7 +469,7 @@ name = "exceptiongroup"
|
|||
version = "1.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" }
|
||||
wheels = [
|
||||
|
@ -482,9 +482,9 @@ version = "3.1.1"
|
|||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "blinker" },
|
||||
{ name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "click", version = "8.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "importlib-metadata", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "click", version = "8.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "importlib-metadata", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "itsdangerous" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "markupsafe" },
|
||||
|
@ -521,7 +521,7 @@ dependencies = [
|
|||
{ name = "packaging" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "trove-classifiers" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8f/8a/cc1debe3514da292094f1c3a700e4ca25442489731ef7c0814358816bb03/hatchling-1.27.0.tar.gz", hash = "sha256:971c296d9819abb3811112fc52c7a9751c8d381898f36533bb16f9791e941fd6", size = 54983, upload-time = "2024-12-15T17:08:11.894Z" }
|
||||
|
@ -621,7 +621,7 @@ name = "markdown"
|
|||
version = "3.8.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "importlib-metadata", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "importlib-metadata", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d7/c2/4ab49206c17f75cb08d6311171f2d65798988db4360c4d1485bd0eedd67c/markdown-3.8.2.tar.gz", hash = "sha256:247b9a70dd12e27f67431ce62523e675b866d254f900c4fe75ce3dda62237c45", size = 362071, upload-time = "2025-06-19T17:12:44.483Z" }
|
||||
wheels = [
|
||||
|
@ -712,7 +712,7 @@ source = { registry = "https://pypi.org/simple" }
|
|||
dependencies = [
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/81/69/92c7fa98112e4d9eb075a239caa4ef4649ad7d441545ccffbd5e34607cbb/mypy-1.16.1.tar.gz", hash = "sha256:6bd00a0a2094841c5e47e7374bb42b83d64c527a502e3334e1173a0c24437bab", size = 3324747, upload-time = "2025-06-16T16:51:35.145Z" }
|
||||
|
@ -886,7 +886,7 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "wrapt", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "wrapt", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/27/9a/4e949d0a281c5dd45c8d5b02b03fe32044936234675e967de49317a1daee/pip_system_certs-4.0.tar.gz", hash = "sha256:db8e6a31388d9795ec9139957df1a89fa5274fb66164456fd091a5d3e94c350c", size = 5622, upload-time = "2022-11-04T11:01:12.537Z" }
|
||||
wheels = [
|
||||
|
@ -903,7 +903,7 @@ resolution-markers = [
|
|||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "pip", marker = "python_full_version >= '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pip", marker = "python_full_version >= '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/0c/a338ae5d49192861cf54da4d5c2af0efe47edbaa0827995b284005366ca5/pip_system_certs-5.2.tar.gz", hash = "sha256:80b776b5cf17191bf99d313699b7fce2fdb84eb7bbb225fd134109a82706406f", size = 5408, upload-time = "2025-06-17T23:33:15.322Z" }
|
||||
wheels = [
|
||||
|
@ -965,8 +965,8 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "pyqt6-qt6", version = "6.6.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-sip", version = "13.6.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-qt6", version = "6.6.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-sip", version = "13.6.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/2b/6fe0409501798abc780a70cab48c39599742ab5a8168e682107eaab78fca/PyQt6-6.6.1.tar.gz", hash = "sha256:9f158aa29d205142c56f0f35d07784b8df0be28378d20a97bcda8bd64ffd0379", size = 1043203, upload-time = "2023-12-04T10:37:27.406Z" }
|
||||
wheels = [
|
||||
|
@ -986,8 +986,8 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "pyqt6-qt6", version = "6.7.3", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-qt6", version = "6.7.3", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d1/f9/b0c2ba758b14a7219e076138ea1e738c068bf388e64eee68f3df4fc96f5a/PyQt6-6.7.1.tar.gz", hash = "sha256:3672a82ccd3a62e99ab200a13903421e2928e399fda25ced98d140313ad59cb9", size = 1051212, upload-time = "2024-07-19T08:49:58.247Z" }
|
||||
wheels = [
|
||||
|
@ -1010,8 +1010,8 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "pyqt6-qt6", version = "6.8.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-qt6", version = "6.8.1", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e9/0a/accbebed526158ab2aedd5c84d238159754bd99f481082b3fe7f374c6a3b/PyQt6-6.8.0.tar.gz", hash = "sha256:6d8628de4c2a050f0b74462e4c9cb97f839bf6ffabbca91711722ffb281570d9", size = 1061357, upload-time = "2024-12-12T15:30:42.021Z" }
|
||||
wheels = [
|
||||
|
@ -1200,9 +1200,9 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "pyqt6", version = "6.6.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-sip", version = "13.6.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.6.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6", version = "6.6.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-sip", version = "13.6.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.6.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt66' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/49/9a/69db3a2ab1ba43f762144a66f0375540e195e107a1049d7263ab48ebc9cc/PyQt6_WebEngine-6.6.0.tar.gz", hash = "sha256:d50b984c3f85e409e692b156132721522d4e8cf9b6c25e0cf927eea2dfb39487", size = 31817, upload-time = "2023-10-30T10:57:13.211Z" }
|
||||
wheels = [
|
||||
|
@ -1222,9 +1222,9 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "pyqt6", version = "6.7.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.7.3", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6", version = "6.7.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.7.3", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/87/88/230ec599944edf941f4cca8d1439e3a9c8c546715434eee05dce7ff032ed/PyQt6_WebEngine-6.7.0.tar.gz", hash = "sha256:68edc7adb6d9e275f5de956881e79cca0d71fad439abeaa10d823bff5ac55001", size = 32593, upload-time = "2024-04-26T08:37:08.355Z" }
|
||||
wheels = [
|
||||
|
@ -1245,9 +1245,9 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "pyqt6", version = "6.8.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.8.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-3-aqt-qt' or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6", version = "6.8.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-sip", version = "13.10.2", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pyqt6-webengine-qt6", version = "6.8.1", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (extra != 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cd/c8/cadaa950eaf97f29e48c435e274ea5a81c051e745a3e2f5d9d994b7a6cda/PyQt6_WebEngine-6.8.0.tar.gz", hash = "sha256:64045ea622b6a41882c2b18f55ae9714b8660acff06a54e910eb72822c2f3ff2", size = 34203, upload-time = "2024-12-12T15:34:35.573Z" }
|
||||
wheels = [
|
||||
|
@ -1309,7 +1309,7 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "pyqt6-webenginesubwheel-qt6", marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pyqt6-webenginesubwheel-qt6", marker = "extra == 'extra-3-aqt-qt67' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt' and extra != 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/06/35/570d072bec7c114b5d155d990e2b8339223e230e9276bdf806a20f71e50d/PyQt6_WebEngine_Qt6-6.7.3-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:68812b2a5d0d417ce32dc4d11a304e7838e02c51013712e7533faf03448672d9", size = 26214456, upload-time = "2024-09-29T16:27:20.257Z" },
|
||||
|
@ -1382,13 +1382,13 @@ name = "pytest"
|
|||
version = "8.4.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "pygments" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" }
|
||||
wheels = [
|
||||
|
@ -1476,7 +1476,7 @@ source = { registry = "https://pypi.org/simple" }
|
|||
dependencies = [
|
||||
{ name = "attrs" },
|
||||
{ name = "rpds-py" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" }
|
||||
wheels = [
|
||||
|
@ -1696,24 +1696,24 @@ resolution-markers = [
|
|||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "alabaster", version = "0.7.16", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "babel", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "colorama", marker = "(python_full_version < '3.10' and sys_platform == 'win32') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "docutils", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "imagesize", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "importlib-metadata", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "jinja2", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "packaging", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pygments", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "requests", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "snowballstemmer", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "alabaster", version = "0.7.16", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "babel", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "colorama", marker = "(python_full_version < '3.10' and sys_platform == 'win32') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (python_full_version >= '3.10' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "docutils", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "imagesize", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "importlib-metadata", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "jinja2", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "packaging", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pygments", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "requests", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "snowballstemmer", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5b/be/50e50cb4f2eff47df05673d361095cafd95521d2a22521b920c67a372dcb/sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", size = 8067911, upload-time = "2024-07-20T14:46:56.059Z" }
|
||||
wheels = [
|
||||
|
@ -1728,23 +1728,23 @@ resolution-markers = [
|
|||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "alabaster", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "babel", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "colorama", marker = "(python_full_version == '3.10.*' and sys_platform == 'win32') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "docutils", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "imagesize", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "jinja2", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "packaging", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pygments", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "requests", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "snowballstemmer", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-applehelp", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-devhelp", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-htmlhelp", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-jsmath", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-qthelp", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-serializinghtml", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "tomli", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "alabaster", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "babel", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "colorama", marker = "(python_full_version == '3.10.*' and sys_platform == 'win32') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (python_full_version != '3.10.*' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "docutils", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "imagesize", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "jinja2", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "packaging", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pygments", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "requests", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "snowballstemmer", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-applehelp", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-devhelp", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-htmlhelp", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-jsmath", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-qthelp", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-serializinghtml", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "tomli", marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" }
|
||||
wheels = [
|
||||
|
@ -1760,23 +1760,23 @@ resolution-markers = [
|
|||
"python_full_version == '3.11.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "alabaster", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "babel", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "colorama", marker = "(python_full_version >= '3.11' and sys_platform == 'win32') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "docutils", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "imagesize", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "jinja2", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "packaging", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "pygments", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "requests", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "roman-numerals-py", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "snowballstemmer", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "alabaster", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "babel", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "colorama", marker = "(python_full_version >= '3.11' and sys_platform == 'win32') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (python_full_version < '3.11' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (sys_platform != 'win32' and extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "docutils", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "imagesize", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "jinja2", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "packaging", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "pygments", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "requests", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "roman-numerals-py", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "snowballstemmer", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" }
|
||||
wheels = [
|
||||
|
@ -1791,10 +1791,10 @@ dependencies = [
|
|||
{ name = "astroid" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "pyyaml" },
|
||||
{ name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "stdlib-list", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "stdlib-list", marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7f/a8/22b379a2a75ccb881217d3d4ae56d7d35f2d1bb4c8c0c51d0253676746a1/sphinx_autoapi-3.6.0.tar.gz", hash = "sha256:c685f274e41d0842ae7e199460c322c4bd7fec816ccc2da8d806094b4f64af06", size = 55417, upload-time = "2025-02-18T01:50:55.241Z" }
|
||||
wheels = [
|
||||
|
@ -1807,9 +1807,9 @@ version = "3.0.2"
|
|||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "docutils" },
|
||||
{ name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinxcontrib-jquery" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463, upload-time = "2024-11-13T11:06:04.545Z" }
|
||||
|
@ -1849,9 +1849,9 @@ name = "sphinxcontrib-jquery"
|
|||
version = "4.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt69') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt69')" },
|
||||
{ name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
{ name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt66') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt67') or (extra == 'extra-3-aqt-qt66' and extra == 'extra-3-aqt-qt68') or (extra == 'extra-3-aqt-qt67' and extra == 'extra-3-aqt-qt68')" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" }
|
||||
wheels = [
|
||||
|
|
Loading…
Reference in a new issue