mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
expose pyqt6 packages - not yet used
This commit is contained in:
parent
2a3072191f
commit
1701937cba
7 changed files with 254 additions and 1 deletions
6
defs.bzl
6
defs.bzl
|
@ -9,6 +9,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install
|
|||
load("@io_bazel_rules_sass//:defs.bzl", "sass_repositories")
|
||||
load("@com_github_ali5h_rules_pip//:defs.bzl", "pip_import")
|
||||
load("//pip/pyqt5:defs.bzl", "install_pyqt5")
|
||||
load("//pip/pyqt6:defs.bzl", "install_pyqt6")
|
||||
|
||||
anki_version = "2.1.49"
|
||||
|
||||
|
@ -43,6 +44,11 @@ def setup_deps():
|
|||
python_runtime = "@python//:python",
|
||||
)
|
||||
|
||||
install_pyqt6(
|
||||
name = "pyqt6",
|
||||
python_runtime = "@python//:python",
|
||||
)
|
||||
|
||||
node_repositories(package_json = ["@ankidesktop//:package.json"])
|
||||
|
||||
yarn_install(
|
||||
|
|
0
pip/pyqt6/BUILD.bazel
Normal file
0
pip/pyqt6/BUILD.bazel
Normal file
47
pip/pyqt6/defs.bzl
Normal file
47
pip/pyqt6/defs.bzl
Normal file
|
@ -0,0 +1,47 @@
|
|||
# based off https://github.com/ali5h/rules_pip/blob/master/defs.bzl
|
||||
|
||||
pip_vendor_label = Label("@com_github_ali5h_rules_pip//:third_party/py/easy_install.py")
|
||||
|
||||
def _execute(repository_ctx, arguments, quiet = False):
|
||||
pip_vendor = str(repository_ctx.path(pip_vendor_label).dirname)
|
||||
return repository_ctx.execute(arguments, environment = {
|
||||
"PYTHONPATH": pip_vendor,
|
||||
}, quiet = quiet)
|
||||
|
||||
def _install_pyqt6_impl(repository_ctx):
|
||||
python_interpreter = repository_ctx.attr.python_interpreter
|
||||
if repository_ctx.attr.python_runtime:
|
||||
python_interpreter = repository_ctx.path(repository_ctx.attr.python_runtime)
|
||||
|
||||
args = [
|
||||
python_interpreter,
|
||||
repository_ctx.path(repository_ctx.attr._script),
|
||||
repository_ctx.path("."),
|
||||
]
|
||||
|
||||
result = _execute(repository_ctx, args, quiet = repository_ctx.attr.quiet)
|
||||
if result.return_code:
|
||||
fail("failed: %s (%s)" % (result.stdout, result.stderr))
|
||||
|
||||
install_pyqt6 = repository_rule(
|
||||
attrs = {
|
||||
"python_interpreter": attr.string(default = "python", doc = """
|
||||
The command to run the Python interpreter used to invoke pip and unpack the
|
||||
wheels.
|
||||
"""),
|
||||
"python_runtime": attr.label(doc = """
|
||||
The label to the Python run-time interpreted used to invoke pip and unpack the wheels.
|
||||
If the label is specified it will overwrite the python_interpreter attribute.
|
||||
"""),
|
||||
"_script": attr.label(
|
||||
executable = True,
|
||||
default = Label("//pip/pyqt6:install_pyqt6.py"),
|
||||
cfg = "host",
|
||||
),
|
||||
"quiet": attr.bool(
|
||||
default = True,
|
||||
doc = "If stdout and stderr should be printed to the terminal.",
|
||||
),
|
||||
},
|
||||
implementation = _install_pyqt6_impl,
|
||||
)
|
196
pip/pyqt6/install_pyqt6.py
Normal file
196
pip/pyqt6/install_pyqt6.py
Normal file
|
@ -0,0 +1,196 @@
|
|||
# based on https://github.com/ali5h/rules_pip/blob/master/src/whl.py
|
||||
# MIT
|
||||
|
||||
"""downloads and parses info of a pkg and generates a BUILD file for it"""
|
||||
import argparse
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pkginfo
|
||||
|
||||
from pip._internal.commands import create_command
|
||||
from pip._vendor import pkg_resources
|
||||
|
||||
|
||||
def _create_nspkg_init(dirpath):
|
||||
"""Creates an init file to enable namespacing"""
|
||||
if not os.path.exists(dirpath):
|
||||
# Handle missing namespace packages by ignoring them
|
||||
return
|
||||
nspkg_init = os.path.join(dirpath, "__init__.py")
|
||||
with open(nspkg_init, "w") as nspkg:
|
||||
nspkg.write("__path__ = __import__('pkgutil').extend_path(__path__, __name__)")
|
||||
|
||||
|
||||
def install_package(pkg, directory, pip_args):
|
||||
"""Downloads wheel for a package. Assumes python binary provided has
|
||||
pip and wheel package installed.
|
||||
|
||||
Args:
|
||||
pkg: package name
|
||||
directory: destination directory to download the wheel file in
|
||||
python: python binary path used to run pip command
|
||||
pip_args: extra pip args sent to pip
|
||||
Returns:
|
||||
str: path to the wheel file
|
||||
"""
|
||||
pip_args = [
|
||||
"--isolated",
|
||||
"--disable-pip-version-check",
|
||||
"--target",
|
||||
directory,
|
||||
"--no-deps",
|
||||
"--ignore-requires-python",
|
||||
pkg,
|
||||
] + pip_args
|
||||
cmd = create_command("install")
|
||||
cmd.main(pip_args)
|
||||
|
||||
# need dist-info directory for pkg_resources to be able to find the packages
|
||||
dist_info = glob.glob(os.path.join(directory, "*.dist-info"))[0]
|
||||
# fix namespace packages by adding proper __init__.py files
|
||||
namespace_packages = os.path.join(dist_info, "namespace_packages.txt")
|
||||
if os.path.exists(namespace_packages):
|
||||
with open(namespace_packages) as nspkg:
|
||||
for line in nspkg.readlines():
|
||||
namespace = line.strip().replace(".", os.sep)
|
||||
if namespace:
|
||||
_create_nspkg_init(os.path.join(directory, namespace))
|
||||
|
||||
# PEP 420 -- Implicit Namespace Packages
|
||||
if (sys.version_info[0], sys.version_info[1]) >= (3, 3):
|
||||
for dirpath, dirnames, filenames in os.walk(directory):
|
||||
# we are only interested in dirs with no init file
|
||||
if "__init__.py" in filenames:
|
||||
dirnames[:] = []
|
||||
continue
|
||||
# remove bin and dist-info dirs
|
||||
for ignored in ("bin", os.path.basename(dist_info)):
|
||||
if ignored in dirnames:
|
||||
dirnames.remove(ignored)
|
||||
_create_nspkg_init(dirpath)
|
||||
|
||||
return pkginfo.Wheel(dist_info)
|
||||
|
||||
|
||||
def _cleanup(directory, pattern):
|
||||
for p in glob.glob(os.path.join(directory, pattern)):
|
||||
shutil.rmtree(p)
|
||||
|
||||
|
||||
fix_none = re.compile(r"(\s*None) =")
|
||||
|
||||
|
||||
def copy_and_fix_pyi(source, dest):
|
||||
"Fix broken PyQt types."
|
||||
with open(source) as input_file:
|
||||
with open(dest, "w") as output_file:
|
||||
for line in input_file.readlines():
|
||||
# inheriting from the missing sip.sipwrapper definition
|
||||
# causes missing attributes not to be detected, as it's treating
|
||||
# the class as inheriting from Any
|
||||
line = line.replace("PyQt6.sip.wrapper", "object")
|
||||
line = line.replace("PyQt6.sip.wrapper", "object")
|
||||
# # remove blanket getattr in QObject which also causes missing
|
||||
# # attributes not to be detected
|
||||
if "def __getattr__(self, name: str) -> typing.Any" in line:
|
||||
continue
|
||||
output_file.write(line)
|
||||
|
||||
|
||||
def merge_files(root, source):
|
||||
for dirpath, _dirnames, filenames in os.walk(source):
|
||||
target_dir = os.path.join(root, os.path.relpath(dirpath, source))
|
||||
if not os.path.exists(target_dir):
|
||||
os.mkdir(target_dir)
|
||||
for fname in filenames:
|
||||
source_path = os.path.join(dirpath, fname)
|
||||
target_path = os.path.join(target_dir, fname)
|
||||
if not os.path.exists(target_path):
|
||||
if fname.endswith(".pyi"):
|
||||
copy_and_fix_pyi(source_path, target_path)
|
||||
else:
|
||||
shutil.copy2(source_path, target_path)
|
||||
|
||||
|
||||
def main():
|
||||
base = sys.argv[1]
|
||||
|
||||
local_site_packages = os.environ.get("PYTHON_SITE_PACKAGES")
|
||||
if local_site_packages:
|
||||
subprocess.run(
|
||||
[
|
||||
"rsync",
|
||||
"-ai",
|
||||
"--include=PyQt**",
|
||||
"--exclude=*",
|
||||
local_site_packages,
|
||||
base + "/",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
with open(os.path.join(base, "__init__.py"), "w") as file:
|
||||
pass
|
||||
|
||||
else:
|
||||
packages = [
|
||||
("pyqt6", "pyqt6==6.2.0"),
|
||||
("pyqt6-qt6", "pyqt6-qt6==6.2.0"),
|
||||
("pyqt6-webengine", "pyqt6-webengine==6.2.0"),
|
||||
("pyqt6-webengine-qt6", "pyqt6-webengine-qt6==6.2.0"),
|
||||
("pyqt6-sip", "pyqt6_sip==13.1.0"),
|
||||
]
|
||||
|
||||
for (name, with_version) in packages:
|
||||
# install package in subfolder
|
||||
folder = os.path.join(base, "temp")
|
||||
_pkg = install_package(with_version, folder, [])
|
||||
# merge into parent
|
||||
merge_files(base, folder)
|
||||
shutil.rmtree(folder)
|
||||
|
||||
# add missing py.typed file
|
||||
with open(os.path.join(base, "py.typed"), "w") as file:
|
||||
pass
|
||||
|
||||
result = """
|
||||
load("@rules_python//python:defs.bzl", "py_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
py_library(
|
||||
name = "pkg",
|
||||
srcs = glob(["**/*.py"]),
|
||||
data = glob(["**/*"], exclude = [
|
||||
"**/*.py",
|
||||
"**/*.pyc",
|
||||
"**/* *",
|
||||
"BUILD",
|
||||
"WORKSPACE",
|
||||
"bin/*",
|
||||
"__pycache__",
|
||||
# these make building slower
|
||||
"Qt/qml/**",
|
||||
"**/*.sip",
|
||||
"**/*.png",
|
||||
]),
|
||||
# This makes this directory a top-level in the python import
|
||||
# search path for anything that depends on this.
|
||||
imports = ["."],
|
||||
)
|
||||
"""
|
||||
|
||||
# clean up
|
||||
_cleanup(base, "__pycache__")
|
||||
|
||||
with open(os.path.join(base, "BUILD"), "w") as f:
|
||||
f.write(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,6 +1,6 @@
|
|||
[MASTER]
|
||||
persistent = no
|
||||
extension-pkg-whitelist=PyQt5
|
||||
extension-pkg-whitelist=PyQt5,PyQt6
|
||||
ignore = forms,hooks_gen.py
|
||||
|
||||
[TYPECHECK]
|
||||
|
|
|
@ -67,3 +67,6 @@ ignore_missing_imports = True
|
|||
disallow_untyped_defs=false
|
||||
[mypy-anki.*]
|
||||
disallow_untyped_defs=false
|
||||
|
||||
[mypy-PyQt6.*]
|
||||
ignore_errors = True
|
|
@ -7,6 +7,7 @@ from pathlib import Path
|
|||
|
||||
nonstandard_header = {
|
||||
"pip/pyqt5/install_pyqt5.py",
|
||||
"pip/pyqt6/install_pyqt6.py",
|
||||
"pylib/anki/importing/pauker.py",
|
||||
"pylib/anki/importing/supermemo_xml.py",
|
||||
"pylib/anki/statsbg.py",
|
||||
|
|
Loading…
Reference in a new issue