py2ls 0.2.4.34__tar.gz → 0.2.4.36__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/PKG-INFO +6 -7
- py2ls-0.2.4.36/py2ls/data/RealESRGAN_x4plus.pth +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/ips.py +350 -33
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/netfinder.py +30 -40
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/ocr.py +2 -2
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/pyproject.toml +11 -7
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/README.md +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.DS_Store +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/.DS_Store +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/COMMIT_EDITMSG +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/FETCH_HEAD +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/HEAD +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/config +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/description +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/applypatch-msg.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/commit-msg.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/fsmonitor-watchman.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/post-update.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/pre-applypatch.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/pre-commit.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/pre-merge-commit.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/pre-push.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/pre-rebase.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/pre-receive.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/prepare-commit-msg.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/push-to-checkout.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/hooks/update.sample +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/index +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/info/exclude +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/logs/HEAD +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/logs/refs/heads/main +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/logs/refs/remotes/origin/HEAD +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/logs/refs/remotes/origin/main +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/.DS_Store +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/01/d5bd8065e6860c0bd23ff9fa57161806a099e1 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/09/08da26de58c114225ad81f484b80bf5d351b34 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/0b/409e1bc918277010f5679b402d1d1dda53e15c +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/12/c2808a1b3a4d0892a4154dfba1e2ae3770fa73 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/14/449a0e6ba4ea2f1a73acf63ef91c9c6193f9ed +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/15/a8e468aacfcb440e090020f36d0b985d45da23 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/1a/b4585881a6a42889f01aa0cfe25fd5acfaf46f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/1c/3f92adda34344bcbbbf9d409c79855ae2aaea8 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/1c/9314c5f69b9390068a2a8616875d974849d71f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/1d/fe9d9633b24ea560354f4f93d39c6e5f163ea0 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/20/72c28e83f4347959d29f7b3a6c1fc3e4ee6b59 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/24/6b368b986f758630c46dc02b7fa512b53422f7 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/25/b796accd261b9135fd32a2c00785f68edf6c46 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/27/aa6074f652bc6f7078f8647489d9ee8e24f0e2 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/28/c2969d785c1b892c2a96b3f00eba63a59811b3 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/2a/ae95d517d213b660bf4f65a4e0cfae7bb893eb +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/2a/fdf45791a26d42ccead35ace76a8f0b2a56561 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/30/a2f8da47ee947811dc8d993f5a06a45de374f4 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/32/fd627b62fad7cf3b2f9e34ab9777126a0987ad +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/34/9e31b6a3634cea102ce5588b98c11cc1738605 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/34/b6f3a2ee84f39bed4eee57f2c0e0afb994feb1 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/35/1a5f491ab97eee9d1ee699478d75a8bb5d3dc2 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/36/b4a1b7403abc6c360f8fe2cb656ab945254971 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/36/e56a361f526eafa59c5235a5c990bf288b5f9c +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/36/ef43e50009e59db11812c258846d9e38718173 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/39/7ead045fbbcfb17c62019eb18fe21ed05dbee5 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/39/b13be65125556784e44c7a1d9821703c7ab67e +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/3b/507acc7f23391644cc0b824b1e79fd2677a362 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/3b/bd972aa7ad680858f8dfbd0f7fcd97756f0d6f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/3c/bbe5f4173d165127b9ad96119f1ec24c306ffc +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/3d/9d10d27724657a436c65a6254bfd213d4b3562 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/3f/d6561300938afbb3d11976cf9c8f29549280d9 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/41/dcf4b3bf0460946b2da93776cf9e836d62178f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/43/dbd49b2ee367c5434dd545e3b5795434f2ef0b +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/45/b1b6178bacbfc997811a998b5cc60c1ea7fac8 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/47/6cbd5a7c5e35cddef2f8a38bdc4896d403b095 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/48/a88fc5806305d0bb0755ee6801161b79696972 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/4f/7afb40dff2153d857fc85748c2eecb85125042 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/50/08ddfcf53c02e82d7eee2e57c38e5672ef89f6 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/53/e0deb1cb4c2c606bced6e7f9a66b0fda60980d +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/56/e4e8b2d5545e0256090f45aa8fc42c5fe067d0 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/57/63d0c52f5c9c69e89d514a1f96034947abe21a +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/57/bd1c0199483ab316235b094543b85edec6c35e +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/58/20a729045d4dc7e37ccaf8aa8eec126850afe2 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/59/380c4c26bdcd4d9b71ae3e2e35f05b3f26c5ab +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/5a/192565abf89c9d765af846ce6d53a92b1ce7ad +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/60/f273eb1c412d916fa3f11318a7da7a9911b52a +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/61/570cec8c061abe74121f27f5face6c69b98f99 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/62/4488173ed2c8936fa5cea3cf5dd3f26a30b86e +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/62/7c81b23b4e56e87b042b650b0103653cc9e34a +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/62/d90ccf8cbefdc2e4fd475e7c6f4f76e9fdf801 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/63/100154b27846e8010e55b6bf4b3d7762c14c5f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/64/27a4edff08f93d98f511418423f09f2ab90bcd +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/66/6227eeeba24073e63811e89f1449f3d958f183 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/66/c998778721d424bd0aae80602dabbffa93af2e +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/68/6df3072c8b025fb18106ed2df505994ad062a9 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/69/13c452ca319f7cbf6a0836dc10a5bb033c84e4 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/6a/52e747a2b349b128d1490d9e896d2323818eb7 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/6b/7fde264d93a7a0986d394c46c7650d0ce2ab92 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/6c/cebb29b7f3f5b0c889f6dadbf9ff066554587d +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/6d/c2cdf4a84e538e5d4777486aeff87e42f41799 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/6d/ee29dbdcc84edeeacede105110446f3ccac963 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/71/36b2074a2754be8b58127d82250e5b37e3c373 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/72/245a05b0966011cb381e6b32b0465000e969ab +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/72/e4179337639859678ddaecf38b16f33aaec8e1 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/78/063f4c863fc371ec0313303c0a81283b35d9b6 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/78/3d4167bc95c9d2175e0df03ef1c1c880ba75ab +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/79/7ae089b2212a937840e215276005ce76881307 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/7e/5956c806b5edc344d46dab599dec337891ba1f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/81/8f26b7bf042269729020cf944fc362d66ba27e +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/82/70b319ce4046854fbe7dc41054b6c2d112dab2 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/84/59071b722a255b774a80b27746033f8141ab39 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/85/aee46f478e9afdb84d50a05242c53b04ed2e21 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/86/e288b46f8fe179907e4413f665aeb5053fddb1 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/87/ef1fc3f7f1ddc4d0ab9b3e65381ce9f3388621 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/8b/84f56978e1de8f2ae82abce5f8b3e182d365cd +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/8e/55a7d2b96184030211f20c9b9af201eefcac82 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/91/c69ad88fe0ba94aa7859fb5f7edac5e6f1a3f7 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/94/74152b4b463d70ae5ad07f0c658be3e296026b +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/94/f7dbe88e80c4205a901b71eb8f181974376bba +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/97/1aef09ea939f46b60b9646f8d524c78a9220f4 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/9b/ec5ee2236ee2d5532c36bfd132e23c58fdb69c +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/9d/0df52899fe95279059286d9c0ec42287edc168 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/a1/5389729850729fc7bd78a54f26fce77f30be12 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/a1/906da89d1174f74867800c74c43af36253bd5e +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/a4/63fdd23e5efd713db8a71f316f3a1c7bd60916 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/a5/ec8f74642fbba27f7ea78c53b372ae0c7dedce +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/a7/3e13eafee65c5b8d73ad2d3ea46d0eee82f0d3 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/b0/56be4be89ba6b76949dd641df45bb7036050c8 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/b0/9cd7856d58590578ee1a4f3ad45d1310a97f87 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/b2/18e6a0f0f1c4df8cdefa9852058348abc713b7 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/b3/4f7f271c6d6105e35a6556ffda71d03afe8c96 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/b3/69579064bde9de9a19d114fc33e4e48cc8c0e4 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/b5/61831c7dce8ea51e7ee6b6fa35745f14d8242d +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/b7/2c9e75ab7d0afe594664650aa8f6c772f5ac64 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/bb/81ccc0513f18fc160b54a82861e9a80d23f4f6 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/bb/934eb33bc1a8b85630bf680caffd99560c1b8f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/bf/67907e337021ebff434e02b19b30a741c144af +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/bf/b54d65922ce1dfda1aaa014913a54e7172d0bc +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/c1/20fc812b9ad311c34a3608512d6a9d976bb48e +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/c1/397c6ed72c4e20ef6b9ab83163e9a6baba5b45 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/c4/cba65f1163661999ee4b8ed23342b63bc1300c +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/c6/7f17e5707313600efcb85e9a3fedea35dba591 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/c6/f32aced880bd165a251cb52b26b0c1107e2141 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/cc/45df1d317a2eb63ff1ff3a5f3b4a9f98fd92b5 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/cd/822b3574a88ebdd1ed82fd6983f37e626d52b4 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/cf/0c0d9c6fb09473aaeb7f7e2edbd770c3f2ef3d +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/d2/992df305f4b56a466a2f221aeb182ddd20f418 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/d6/39e8af592cd75a318d8affddd1bcc70c2095f2 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/d6/9ab1c4aadf279936dd778e8346ba60f74705b6 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/d8/4688b54c0040a30976b3a6540bc47adf7ce680 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/d9/005f2cc7fc4e65f14ed5518276007c08cf2fd0 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/d9/c2403fd166ce791b4e9d0c6792ed8342c71fcd +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/d9/dfa5aee51e92a541b707e8e7baea6f06deff98 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/db/141dbaa93594df2a8156182f361ee4db829359 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/db/3f2cd643292057936230b95cf7ec3046affe11 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/db/ffa8ea7bda721d0cee7b9e4ce5b2ef927733ff +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/dc/c2bdbafb3296e09d9ee4955cfa55d275825f94 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/dc/cdbd4266765d840be2ae35ab1752a0fa312c16 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/dd/87fb5f606fe380d81e6fe3a2c98f9f99e3e09b +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/de/214c626ac2dd2685bfaa0bc0fc20f528d014d7 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/df/e0770424b2a19faf507a501ebfc23be8f54e7b +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/e2/f2f8f4c25e62a297fc55f36acc6b01cfbab76f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/e3/1356f90ea6dd0577b5e0b40b206319adcbf085 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/e3/5a4dafc50850cacac7bf76c56db2715cbda2c4 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/e4/6c715352db9fe3c887a635f1916df4ca1f4ff9 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/e5/0580a0bd1e1b3d29f834382b80fceb61d5cf0c +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/e9/391ffe371f1cc43b42ef09b705d9c767c2e14f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/ea/3a18cc75e53792744ef754e05d3f4481768c13 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/ec/40fd8bf8e4c342534a9fc020289e402ba6bc9d +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/ec/d980279432b13f0374b90ca439a6329cdece0f +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/ee/cee64eacaff022dcdc509c0c2b1da492f21060 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/f1/e50757fddc28b445545dc7e2759b54cdd0f42e +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/f4/b64d3107b39e3ad6f540c6607004ea34e6c024 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/f4/ba7f815b886797b73fede071d86e0c134d2bc7 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/f5/61c3c1bf1c9ea9c9d1f556a7be2869f71f3bdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/f6/44a8ff56fa035105fc517cbb1ac46c3d8e349a +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/f7/c98ba5c2f903e603b1f5e63d49fbc8a43815cc +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/f9/045a08e96eb76848fc4d68e3e3e687cca39a2d +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/fa/147e6bb78a2e8db241d231295fd7f1ed061af8 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/objects/fc/292e793ecfd42240ac43be407023bd731fa9e7 +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/refs/.DS_Store +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/refs/heads/main +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/refs/remotes/origin/HEAD +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.git/refs/remotes/origin/main +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.gitattributes +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/.gitignore +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/LICENSE +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/README.md +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/__init__.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/batman.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/bio.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/brain_atlas.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/chat.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/corr.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/correlators.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/.DS_Store +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/db2ls_sql_chtsht.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/docs_links.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/email/email_html_template.html +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/hyper_param_autogluon_zeroshot2024.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/hyper_param_tabrepo_2024.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/lang_code_iso639.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/mygenes_fields_241022.txt +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/sns_info.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/.DS_Store +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/.DS_Store +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style1.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style2.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style3.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style4.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style5.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style6.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style7.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style8.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/example/style9.pdf +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style1.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style10.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style11.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style12.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style2.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style3.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style4.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style5.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style6.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style7.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style8.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/style9.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/.DS_Store +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/grid.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/high-contrast.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/high-vis.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/ieee.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/light.mplstyl +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/muted.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/nature-reviews-latex.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/nature-reviews.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/nature.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/no-latex.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/notebook.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/paper.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/retro.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/sans.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/scatter.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/science.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/std-colors.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/styles/stylelib/vibrant.mplstyle +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/tiles.csv +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/usages_pd.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/data/usages_sns.json +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/db2ls.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/doc.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/ec2ls.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/export_requirements.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/fetch_update.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/freqanalysis.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/ich2ls.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/ml2ls.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/mol.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/nl2ls.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/plot.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/setuptools-70.1.0-py3-none-any.whl +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/sleep_events_detectors.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/stats.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/translator.py +0 -0
- {py2ls-0.2.4.34 → py2ls-0.2.4.36}/py2ls/wb_detector.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: py2ls
|
3
|
-
Version: 0.2.4.
|
3
|
+
Version: 0.2.4.36
|
4
4
|
Summary: py(thon)2(too)ls
|
5
5
|
Author: Jianfeng
|
6
6
|
Author-email: Jianfeng.Liu0413@gmail.com
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.10
|
15
15
|
Classifier: Programming Language :: Python :: 3.11
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
17
|
-
Provides-Extra:
|
17
|
+
Provides-Extra: full
|
18
18
|
Requires-Dist: CacheControl (>=0.13.1)
|
19
19
|
Requires-Dist: Cython (>=3.0.10)
|
20
20
|
Requires-Dist: Deprecated (>=1.2.14)
|
@@ -25,11 +25,6 @@ Requires-Dist: MarkupSafe (>=2.1.5)
|
|
25
25
|
Requires-Dist: PyMatting (>=1.1.12)
|
26
26
|
Requires-Dist: PyOpenGL (>=3.1.6)
|
27
27
|
Requires-Dist: PyPDF2 (>=3.0.1)
|
28
|
-
Requires-Dist: PyQt5 (>=5.15.0)
|
29
|
-
Requires-Dist: PyQt5-Qt5 (>=5.15.0)
|
30
|
-
Requires-Dist: PyQt5_sip (>=12.15.0)
|
31
|
-
Requires-Dist: PyQtWebEngine (>=5.15.0)
|
32
|
-
Requires-Dist: PyQtWebEngine-Qt5 (>=5.15.0)
|
33
28
|
Requires-Dist: PySocks (>=1.7.1)
|
34
29
|
Requires-Dist: PyYAML (>=6.0.1)
|
35
30
|
Requires-Dist: Pygments (>=2.18.0)
|
@@ -123,6 +118,7 @@ Requires-Dist: mne (>=1.7.1)
|
|
123
118
|
Requires-Dist: more-itertools (>=10.3.0)
|
124
119
|
Requires-Dist: mpmath (>=1.3.0)
|
125
120
|
Requires-Dist: msgpack (>=1.0.8)
|
121
|
+
Requires-Dist: msoffcrypto-tool (>=5.4.2)
|
126
122
|
Requires-Dist: mtscomp (>=1.0.2)
|
127
123
|
Requires-Dist: nbclient (>=0.10.0)
|
128
124
|
Requires-Dist: nbconvert (>=7.16.4)
|
@@ -131,6 +127,7 @@ Requires-Dist: neo (>=0.13.1)
|
|
131
127
|
Requires-Dist: nest-asyncio (>=1.6.0)
|
132
128
|
Requires-Dist: networkx (>=3.3)
|
133
129
|
Requires-Dist: nltk (>=3.8.1)
|
130
|
+
Requires-Dist: nuitka (>=2.5.9)
|
134
131
|
Requires-Dist: numba (>=0.59.1)
|
135
132
|
Requires-Dist: numcodecs (>=0.13.0)
|
136
133
|
Requires-Dist: numerizer (>=0.2.3)
|
@@ -139,6 +136,7 @@ Requires-Dist: onnxruntime (>=1.18.1)
|
|
139
136
|
Requires-Dist: opencv-contrib-python (>=4.10.0.84)
|
140
137
|
Requires-Dist: opencv-python (>=4.10.0.84)
|
141
138
|
Requires-Dist: opencv-python-headless (>=4.10.0.84)
|
139
|
+
Requires-Dist: openpyxl (>=3.1.5)
|
142
140
|
Requires-Dist: outcome (>=1.3.0.post0)
|
143
141
|
Requires-Dist: packaging (>=24.1)
|
144
142
|
Requires-Dist: pandas (>=2.2.2)
|
@@ -199,6 +197,7 @@ Requires-Dist: rpds-py (>=0.18.1)
|
|
199
197
|
Requires-Dist: scikit-image (>=0.23.2)
|
200
198
|
Requires-Dist: scikit-learn (>=1.5.1)
|
201
199
|
Requires-Dist: scipy (>=1.14.0)
|
200
|
+
Requires-Dist: scrapy (>=2.12.0)
|
202
201
|
Requires-Dist: seaborn (>=0.13.2)
|
203
202
|
Requires-Dist: selenium (>=4.23.1)
|
204
203
|
Requires-Dist: setuptools (>=70.3.0)
|
Binary file
|
@@ -32,10 +32,16 @@ def backup(
|
|
32
32
|
tar="/Users/macjianfeng/Dropbox/github/python/py2ls/py2ls/",
|
33
33
|
kind="py",
|
34
34
|
overwrite=True,
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
reverse=False,
|
36
|
+
verbose=False
|
37
|
+
):
|
38
|
+
if reverse:
|
39
|
+
src, tar = tar,src
|
40
|
+
print(f"reversed")
|
41
|
+
f = listdir(src, kind, verbose=verbose)
|
42
|
+
[copy(i, tar, overwrite=overwrite, verbose=verbose) for i in f.path]
|
43
|
+
print(f"all files are copied from {os.path.basename(src)} to {tar}") if verbose else None
|
44
|
+
|
39
45
|
def run_once_within(duration=60, reverse=False): # default 60s
|
40
46
|
import time
|
41
47
|
|
@@ -2693,13 +2699,41 @@ def fload(fpath, kind=None, **kwargs):
|
|
2693
2699
|
def load_excel(fpath, **kwargs):
|
2694
2700
|
engine = kwargs.get("engine", "openpyxl")
|
2695
2701
|
verbose = kwargs.pop("verbose", False)
|
2696
|
-
|
2697
|
-
|
2698
|
-
|
2702
|
+
password=kwargs.pop("password",None)
|
2703
|
+
|
2704
|
+
if not password:
|
2705
|
+
if run_once_within(reverse=True):
|
2706
|
+
use_pd("read_excel", verbose=verbose)
|
2707
|
+
df = pd.read_excel(fpath, engine=engine, **kwargs)
|
2708
|
+
try:
|
2709
|
+
meta = pd.ExcelFile(fpath)
|
2710
|
+
print(f"n_sheet={len(meta.sheet_names)},\t'sheetname = 0 (default)':")
|
2711
|
+
[print(f"{i}:\t{i_}") for i, i_ in enumerate(meta.sheet_names)]
|
2712
|
+
except:
|
2713
|
+
pass
|
2714
|
+
return df
|
2715
|
+
#* needs a password?
|
2716
|
+
import msoffcrypto # pip install msoffcrypto-tool
|
2717
|
+
from io import BytesIO
|
2718
|
+
|
2719
|
+
# Open the encrypted Excel file
|
2720
|
+
with open(fpath, 'rb') as f:
|
2721
|
+
try:
|
2722
|
+
office_file = msoffcrypto.OfficeFile(f)
|
2723
|
+
office_file.load_key(password=password) # Provide the password
|
2724
|
+
decrypted = BytesIO()
|
2725
|
+
office_file.decrypt(decrypted)
|
2726
|
+
except:
|
2727
|
+
office_file = msoffcrypto.OfficeFile(f)
|
2728
|
+
office_file.load_key(password=depass(password)) # Provide the password
|
2729
|
+
decrypted = BytesIO()
|
2730
|
+
office_file.decrypt(decrypted)
|
2731
|
+
decrypted.seek(0)
|
2732
|
+
df = pd.read_excel(decrypted, engine=engine, **kwargs)
|
2699
2733
|
try:
|
2700
|
-
|
2701
|
-
print(f"n_sheet={len(
|
2702
|
-
[print(f"{i}:\t{i_}") for i, i_ in enumerate(
|
2734
|
+
meta = pd.ExcelFile(fpath)
|
2735
|
+
print(f"n_sheet={len(meta.sheet_names)},\t'sheetname = 0 (default)':")
|
2736
|
+
[print(f"{i}:\t{i_}") for i, i_ in enumerate(meta.sheet_names)]
|
2703
2737
|
except:
|
2704
2738
|
pass
|
2705
2739
|
return df
|
@@ -3283,11 +3317,16 @@ def fsave(
|
|
3283
3317
|
df = pd.DataFrame(data)
|
3284
3318
|
df.to_csv(fpath, **kwargs_valid)
|
3285
3319
|
|
3286
|
-
|
3320
|
+
|
3321
|
+
def save_xlsx(fpath, data, password=None, **kwargs):
|
3322
|
+
import msoffcrypto
|
3323
|
+
from io import BytesIO
|
3287
3324
|
verbose = kwargs.pop("verbose", False)
|
3288
3325
|
sheet_name = kwargs.pop("sheet_name", "Sheet1")
|
3326
|
+
|
3289
3327
|
if run_once_within(reverse=True):
|
3290
3328
|
use_pd("to_excel", verbose=verbose)
|
3329
|
+
|
3291
3330
|
if any(kwargs):
|
3292
3331
|
format_excel(df=data, filename=fpath, **kwargs)
|
3293
3332
|
else:
|
@@ -3312,16 +3351,30 @@ def fsave(
|
|
3312
3351
|
kwargs.pop(key, None)
|
3313
3352
|
|
3314
3353
|
df = pd.DataFrame(data)
|
3315
|
-
|
3316
|
-
|
3317
|
-
|
3318
|
-
|
3319
|
-
|
3320
|
-
|
3321
|
-
|
3322
|
-
|
3323
|
-
|
3324
|
-
|
3354
|
+
|
3355
|
+
# Write to Excel without password first
|
3356
|
+
temp_file = BytesIO()
|
3357
|
+
df.to_excel(temp_file, sheet_name=sheet_name, index=False, engine="xlsxwriter", **kwargs)
|
3358
|
+
|
3359
|
+
# If a password is provided, encrypt the file
|
3360
|
+
if password:
|
3361
|
+
temp_file.seek(0)
|
3362
|
+
office_file = msoffcrypto.OfficeFile(temp_file)
|
3363
|
+
office_file.load_key(password=password) # Provide the password
|
3364
|
+
|
3365
|
+
# Encrypt and save the file
|
3366
|
+
with open(fpath, 'wb') as encrypted_file:
|
3367
|
+
office_file.encrypt(encrypted_file)
|
3368
|
+
else:
|
3369
|
+
# Save the file without encryption if no password is provided
|
3370
|
+
try:
|
3371
|
+
# Use ExcelWriter with append mode if the file exists
|
3372
|
+
with pd.ExcelWriter(fpath, engine="openpyxl", mode="a", if_sheet_exists="new") as writer:
|
3373
|
+
df.to_excel(writer, sheet_name=sheet_name, index=False, **kwargs)
|
3374
|
+
except FileNotFoundError:
|
3375
|
+
# If file doesn't exist, create a new one
|
3376
|
+
df.to_excel(fpath, sheet_name=sheet_name, index=False, **kwargs)
|
3377
|
+
|
3325
3378
|
|
3326
3379
|
def save_ipynb(fpath, data, **kwargs):
|
3327
3380
|
# Split the content by code fences to distinguish between code and markdown
|
@@ -4410,13 +4463,13 @@ def func_list(lib_name, opt="call"):
|
|
4410
4463
|
return list_func(lib_name, opt=opt)
|
4411
4464
|
|
4412
4465
|
|
4413
|
-
def copy(src, dst, overwrite=False):
|
4466
|
+
def copy(src, dst, overwrite=False, verbose=True):
|
4414
4467
|
"""Copy a file from src to dst."""
|
4415
4468
|
try:
|
4416
4469
|
dir_par_dst = os.path.dirname(dst)
|
4417
4470
|
if not os.path.isdir(dir_par_dst):
|
4418
4471
|
mkdir(dir_par_dst)
|
4419
|
-
print(dir_par_dst)
|
4472
|
+
print(dir_par_dst) if verbose else None
|
4420
4473
|
src = Path(src)
|
4421
4474
|
dst = Path(dst)
|
4422
4475
|
if not src.is_dir():
|
@@ -4431,7 +4484,7 @@ def copy(src, dst, overwrite=False):
|
|
4431
4484
|
f"{dst.stem}_{datetime.now().strftime('_%H%M%S')}{dst.suffix}"
|
4432
4485
|
)
|
4433
4486
|
shutil.copy(src, dst)
|
4434
|
-
print(f"\n Done! copy to {dst}\n")
|
4487
|
+
print(f"\n Done! copy to {dst}\n") if verbose else None
|
4435
4488
|
else:
|
4436
4489
|
dst = dst / src.name
|
4437
4490
|
if dst.exists():
|
@@ -4442,7 +4495,7 @@ def copy(src, dst, overwrite=False):
|
|
4442
4495
|
f"{dst.stem}_{datetime.now().strftime('%H%M%S')}"
|
4443
4496
|
)
|
4444
4497
|
shutil.copytree(src, dst)
|
4445
|
-
print(f"\n Done! copy to {dst}\n")
|
4498
|
+
print(f"\n Done! copy to {dst}\n") if verbose else None
|
4446
4499
|
|
4447
4500
|
except Exception as e:
|
4448
4501
|
logging.error(f"Failed {e}")
|
@@ -4452,7 +4505,7 @@ def cut(src, dst, overwrite=False):
|
|
4452
4505
|
return move(src=src, dst=dst, overwrite=overwrite)
|
4453
4506
|
|
4454
4507
|
|
4455
|
-
def move(src, dst, overwrite=False):
|
4508
|
+
def move(src, dst, overwrite=False, verbose=True):
|
4456
4509
|
try:
|
4457
4510
|
dir_par_dst = os.path.dirname(dst)
|
4458
4511
|
if not os.path.isdir(dir_par_dst):
|
@@ -4470,7 +4523,7 @@ def move(src, dst, overwrite=False):
|
|
4470
4523
|
f"{dst.stem}_{datetime.now().strftime('_%H%M%S')}{dst.suffix}"
|
4471
4524
|
)
|
4472
4525
|
shutil.move(src, dst)
|
4473
|
-
print(f"\n Done! moved to {dst}\n")
|
4526
|
+
print(f"\n Done! moved to {dst}\n") if verbose else None
|
4474
4527
|
except Exception as e:
|
4475
4528
|
logging.error(f"Failed to move file from {src} to {dst}: {e}")
|
4476
4529
|
|
@@ -4729,6 +4782,19 @@ def figsave(*args, dpi=300):
|
|
4729
4782
|
plt.savefig(fname, format="emf", dpi=dpi, bbox_inches="tight", pad_inches=0)
|
4730
4783
|
elif ftype.lower() == "fig":
|
4731
4784
|
plt.savefig(fname, format="pdf", bbox_inches="tight", dpi=dpi, pad_inches=0)
|
4785
|
+
|
4786
|
+
elif ftype.lower() == "ico":
|
4787
|
+
# Ensure the image is in a format that can be saved as an icon (e.g., 32x32, 64x64, etc.)
|
4788
|
+
if img is None: # If no image is provided, use the matplotlib figure
|
4789
|
+
img = plt.figure()
|
4790
|
+
img.savefig(fname, dpi=dpi, format="png", bbox_inches="tight")
|
4791
|
+
img = Image.open(fname) # Load the saved figure image
|
4792
|
+
|
4793
|
+
# Resize the image to typical icon sizes and save it as .ico
|
4794
|
+
icon_sizes = [(32, 32), (64, 64), (128, 128), (256, 256)]
|
4795
|
+
img = img.convert("RGBA") # Ensure it has an alpha channel for transparency
|
4796
|
+
img.save(fname, format="ICO", sizes=icon_sizes)
|
4797
|
+
print(f"Icon saved @: {fname} with sizes: {icon_sizes}")
|
4732
4798
|
print(f"\nSaved @: dpi={dpi}\n{fname}")
|
4733
4799
|
|
4734
4800
|
|
@@ -5507,7 +5573,6 @@ def detect_angle(image, by="median", template=None):
|
|
5507
5573
|
print(f"Unknown method {by}: supported methods: {methods}")
|
5508
5574
|
return 0
|
5509
5575
|
|
5510
|
-
|
5511
5576
|
def imgsets(img,
|
5512
5577
|
auto:bool=True,
|
5513
5578
|
size=None,
|
@@ -5594,7 +5659,6 @@ def imgsets(img,
|
|
5594
5659
|
"birefnet-massive": "A pre-trained model with massive dataset.",
|
5595
5660
|
}
|
5596
5661
|
models_support_rem=list(rem_models.keys())
|
5597
|
-
|
5598
5662
|
str_usage="""
|
5599
5663
|
imgsets(dir_img, auto=1, color=1.5, plot_=0)
|
5600
5664
|
imgsets(dir_img, color=2)
|
@@ -5714,7 +5778,7 @@ def imgsets(img,
|
|
5714
5778
|
kwargs = {**auto_enhance(img_update), **kwargs}
|
5715
5779
|
params=["sharp","color","contrast","bright","crop","rotate",'size',"resize",
|
5716
5780
|
"thumbnail","cover","contain","filter","fit","pad",
|
5717
|
-
"rem","rm","back","bg_color","cut",
|
5781
|
+
"rem","rm","back","bg_color","cut","gamma","flip","booster"]
|
5718
5782
|
for k, value in kwargs.items():
|
5719
5783
|
k = strcmp(k, params)[0] # correct the param name
|
5720
5784
|
if "shar" in k.lower():
|
@@ -5735,7 +5799,7 @@ def imgsets(img,
|
|
5735
5799
|
img_update = ImageOps.autocontrast(img_update)
|
5736
5800
|
print("autocontrasted")
|
5737
5801
|
except Exception as e:
|
5738
|
-
print(f"Failed '
|
5802
|
+
print(f"Failed 'auto-contrasted':{e}")
|
5739
5803
|
elif "bri" in k.lower():
|
5740
5804
|
enhancer = ImageEnhance.Brightness(img_update)
|
5741
5805
|
img_update = enhancer.enhance(value)
|
@@ -5780,9 +5844,12 @@ def imgsets(img,
|
|
5780
5844
|
from rembg import remove, new_session
|
5781
5845
|
if verbose:
|
5782
5846
|
preview(rem_models)
|
5847
|
+
|
5848
|
+
print(f"supported modles: {models_support_rem}")
|
5783
5849
|
model=strcmp(model, models_support_rem)[0]
|
5784
5850
|
session = new_session(model)
|
5785
5851
|
if isinstance(value, bool):
|
5852
|
+
print(f"using model:{model}")
|
5786
5853
|
img_update = remove(img_update, session=session)
|
5787
5854
|
elif value and isinstance(value, (int, float, list)):
|
5788
5855
|
if verbose:
|
@@ -5817,6 +5884,7 @@ def imgsets(img,
|
|
5817
5884
|
img_update = remove(img_update, bgcolor=value, session=session)
|
5818
5885
|
elif isinstance(value, str):
|
5819
5886
|
# use custom model
|
5887
|
+
print(f"using model:{strcmp(value, models_support_rem)[0]}")
|
5820
5888
|
img_update = remove(img_update, session=new_session(strcmp(value, models_support_rem)[0]))
|
5821
5889
|
elif "bg" in k.lower() and "color" in k.lower():
|
5822
5890
|
from rembg import remove
|
@@ -5827,7 +5895,33 @@ def imgsets(img,
|
|
5827
5895
|
if len(value) == 3:
|
5828
5896
|
value += (255,)
|
5829
5897
|
img_update = remove(img_update, bgcolor=value)
|
5830
|
-
|
5898
|
+
elif 'boost' in k.lower():
|
5899
|
+
import torch
|
5900
|
+
from realesrgan import RealESRGANer
|
5901
|
+
if verbose:
|
5902
|
+
print("Applying Real-ESRGAN for image reconstruction...")
|
5903
|
+
if isinstance(value, bool):
|
5904
|
+
scale=4
|
5905
|
+
elif isinstance(value, (float, int)):
|
5906
|
+
scale=value
|
5907
|
+
else:
|
5908
|
+
scale=4
|
5909
|
+
|
5910
|
+
# try:
|
5911
|
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
5912
|
+
dir_curr_script = os.path.dirname(os.path.abspath(__file__))
|
5913
|
+
model_path = dir_curr_script + "/data/RealESRGAN_x4plus.pth"
|
5914
|
+
model_RealESRGAN = RealESRGANer(device=device,
|
5915
|
+
scale=scale,
|
5916
|
+
model_path=model_path,
|
5917
|
+
model="RealESRGAN_x4plus"
|
5918
|
+
)
|
5919
|
+
# https://github.com/xinntao/Real-ESRGAN?tab=readme-ov-file#python-script
|
5920
|
+
|
5921
|
+
img_update = model_RealESRGAN.enhance(np.array(img_update))[0]
|
5922
|
+
# except Exception as e:
|
5923
|
+
# print(f"Failed to apply Real-ESRGAN: {e}")
|
5924
|
+
|
5831
5925
|
# elif "ga" in k.lower() and "m" in k.lower():
|
5832
5926
|
# img_update = gamma_correction(img_update, gamma=value)
|
5833
5927
|
# Display the image if requested
|
@@ -10728,4 +10822,227 @@ def mouse(
|
|
10728
10822
|
# "Image not found. Ensure the image is visible and parameters are correct."
|
10729
10823
|
# )
|
10730
10824
|
# except Exception as e:
|
10731
|
-
# print(f"An error occurred: {e}")
|
10825
|
+
# print(f"An error occurred: {e}")
|
10826
|
+
|
10827
|
+
|
10828
|
+
|
10829
|
+
def py2installer(
|
10830
|
+
script_path: str=None,
|
10831
|
+
flatform:str="mingw64",
|
10832
|
+
output_dir: str = "dist",
|
10833
|
+
icon_path: str = None,
|
10834
|
+
extra_data: list = None,
|
10835
|
+
hidden_imports: list = None,
|
10836
|
+
plugins:list=None,
|
10837
|
+
use_nuitka: bool = True,
|
10838
|
+
onefile: bool = True,
|
10839
|
+
console: bool = True,
|
10840
|
+
clean_build: bool = False,
|
10841
|
+
additional_args: list = None,
|
10842
|
+
verbose: bool = True,
|
10843
|
+
use_docker: bool = False,
|
10844
|
+
docker_image: str = "python:3.12-slim",
|
10845
|
+
):
|
10846
|
+
"""
|
10847
|
+
to package Python scripts into standalone application.
|
10848
|
+
|
10849
|
+
script_path (str): Path to the Python script to package.
|
10850
|
+
output_dir (str): Directory where the executable will be stored.
|
10851
|
+
icon_path (str): Path to the .ico file for the executable icon.
|
10852
|
+
extra_data (list): List of additional data files or directories in "source:dest" format.
|
10853
|
+
hidden_imports (list): List of hidden imports to include.
|
10854
|
+
plugins (list): List of plugins imports to include.e.g., 'tk-inter'
|
10855
|
+
use_nuitka (bool): Whether to use Nuitka instead of PyInstaller.
|
10856
|
+
onefile (bool): If True, produces a single executable file.
|
10857
|
+
console (bool): If False, hides the console window (GUI mode).
|
10858
|
+
clean_build (bool): If True, cleans previous build and dist directories.
|
10859
|
+
additional_args (list): Additional arguments for PyInstaller/Nuitka.
|
10860
|
+
verbose (bool): If True, provides detailed logs.
|
10861
|
+
use_docker (bool): If True, uses Docker to package the script.
|
10862
|
+
docker_image (str): Docker image to use for packaging.
|
10863
|
+
|
10864
|
+
"""
|
10865
|
+
|
10866
|
+
import os
|
10867
|
+
import sys
|
10868
|
+
import shutil
|
10869
|
+
import subprocess
|
10870
|
+
import sys
|
10871
|
+
import glob
|
10872
|
+
from pathlib import Path
|
10873
|
+
if run_once_within():
|
10874
|
+
usage_str="""
|
10875
|
+
# build locally
|
10876
|
+
py2installer(
|
10877
|
+
script_path="update_tab.py",
|
10878
|
+
output_dir="dist",
|
10879
|
+
icon_path="icon4app.ico",
|
10880
|
+
extra_data=["dat/*.xlsx:dat"],
|
10881
|
+
hidden_imports=["msoffcrypto", "tkinter", "pandas", "numpy"],
|
10882
|
+
onefile=True,
|
10883
|
+
console=False,
|
10884
|
+
clean_build=True,
|
10885
|
+
verbose=True,
|
10886
|
+
)
|
10887
|
+
# build via docker
|
10888
|
+
py2installer(
|
10889
|
+
"my_script.py",
|
10890
|
+
output_dir="dist",
|
10891
|
+
onefile=True,
|
10892
|
+
clean_build=True,
|
10893
|
+
use_docker=True,
|
10894
|
+
docker_image="python:3.12-slim"
|
10895
|
+
)
|
10896
|
+
"""
|
10897
|
+
print(usage_str)
|
10898
|
+
if verbose:
|
10899
|
+
return
|
10900
|
+
else:
|
10901
|
+
pass
|
10902
|
+
# Check if the script path exists
|
10903
|
+
script_path = Path(script_path)
|
10904
|
+
if not script_path.exists():
|
10905
|
+
raise FileNotFoundError(f"Script '{script_path}' not found.")
|
10906
|
+
|
10907
|
+
# Clean build and dist directories if requested
|
10908
|
+
if clean_build:
|
10909
|
+
for folder in ["build", "dist"]:
|
10910
|
+
folder_path = Path(folder)
|
10911
|
+
if folder_path.exists():
|
10912
|
+
shutil.rmtree(folder_path, ignore_errors=True)
|
10913
|
+
# Recreate the folders
|
10914
|
+
for folder in ["build", "dist"]:
|
10915
|
+
folder_path = Path(folder)
|
10916
|
+
folder_path.mkdir(parents=True, exist_ok=True)
|
10917
|
+
|
10918
|
+
|
10919
|
+
if use_docker:
|
10920
|
+
# Ensure Docker is installed
|
10921
|
+
try:
|
10922
|
+
subprocess.run(["docker", "--version"], check=True, capture_output=True, text=True)
|
10923
|
+
except FileNotFoundError:
|
10924
|
+
raise EnvironmentError("Docker is not installed or not in the PATH.")
|
10925
|
+
|
10926
|
+
# Prepare Docker volume mappings
|
10927
|
+
script_dir = script_path.parent.resolve()
|
10928
|
+
dist_path = Path(output_dir).resolve()
|
10929
|
+
volumes = [
|
10930
|
+
f"{script_dir}:/app:rw",
|
10931
|
+
f"{dist_path}:/output:rw",
|
10932
|
+
]
|
10933
|
+
docker_cmd = [
|
10934
|
+
"docker", "run", "--rm",
|
10935
|
+
"-v", volumes[0],
|
10936
|
+
"-v", volumes[1],
|
10937
|
+
docker_image,
|
10938
|
+
"bash", "-c",
|
10939
|
+
]
|
10940
|
+
|
10941
|
+
# Build the packaging command inside the container
|
10942
|
+
cmd = ["nuitka"] if use_nuitka else ["pyinstaller"]
|
10943
|
+
if onefile:
|
10944
|
+
cmd.append("--onefile")
|
10945
|
+
if not console:
|
10946
|
+
cmd.append("--windowed")
|
10947
|
+
cmd.extend(["--distpath", "/output"])
|
10948
|
+
if icon_path:
|
10949
|
+
cmd.extend(["--icon", f"/app/{Path(icon_path).name}"])
|
10950
|
+
if extra_data:
|
10951
|
+
for data in extra_data:
|
10952
|
+
cmd.extend(["--add-data", f"/app/{data}"])
|
10953
|
+
if hidden_imports:
|
10954
|
+
for hidden in hidden_imports:
|
10955
|
+
cmd.extend(["--hidden-import", hidden])
|
10956
|
+
if additional_args:
|
10957
|
+
cmd.extend(additional_args)
|
10958
|
+
cmd.append(f"/app/{script_path.name}")
|
10959
|
+
|
10960
|
+
# Full command to execute inside the container
|
10961
|
+
docker_cmd.append(" ".join(cmd))
|
10962
|
+
|
10963
|
+
if verbose:
|
10964
|
+
print(f"Running Docker command: {' '.join(docker_cmd)}")
|
10965
|
+
|
10966
|
+
# Run Docker command
|
10967
|
+
try:
|
10968
|
+
subprocess.run(
|
10969
|
+
docker_cmd,
|
10970
|
+
capture_output=not verbose,
|
10971
|
+
text=True,
|
10972
|
+
check=True,
|
10973
|
+
)
|
10974
|
+
except subprocess.CalledProcessError as e:
|
10975
|
+
print(f"Error during Docker packaging:\n{e.stderr}", file=sys.stderr)
|
10976
|
+
raise
|
10977
|
+
else:
|
10978
|
+
# Handle local packaging (native build)
|
10979
|
+
cmd = ["nuitka"]
|
10980
|
+
cmd.append("--standalone") # Make sure to use --standalone for independent environments
|
10981
|
+
if 'min' in flatform.lower():
|
10982
|
+
cmd.append("--mingw64")
|
10983
|
+
if onefile:
|
10984
|
+
cmd.append("--onefile")
|
10985
|
+
if not console:
|
10986
|
+
# cmd.append("--windows-disable-console") # Disabled based on your request
|
10987
|
+
pass
|
10988
|
+
|
10989
|
+
cmd.extend([f"--output-dir={output_dir}"]) # Correct the space issue here
|
10990
|
+
if icon_path:
|
10991
|
+
icon_path = Path(icon_path)
|
10992
|
+
if not icon_path.exists():
|
10993
|
+
raise FileNotFoundError(f"Icon file '{icon_path}' not found.")
|
10994
|
+
cmd.extend([f"--windows-icon-from-ico={icon_path}"])
|
10995
|
+
|
10996
|
+
if extra_data:
|
10997
|
+
for data in extra_data:
|
10998
|
+
if "*" in data:
|
10999
|
+
matches = glob.glob(data.split(":")[0])
|
11000
|
+
for match in matches:
|
11001
|
+
dest = data.split(":")[1]
|
11002
|
+
cmd.extend(
|
11003
|
+
[
|
11004
|
+
"--include-data-file=" if use_nuitka else "--add-data",
|
11005
|
+
f"{match}:{dest}",
|
11006
|
+
]
|
11007
|
+
)
|
11008
|
+
else:
|
11009
|
+
cmd.extend(
|
11010
|
+
["--include-data-file=" if use_nuitka else "--add-data", data]
|
11011
|
+
)
|
11012
|
+
|
11013
|
+
if hidden_imports:
|
11014
|
+
cmd.extend([f"--nofollow-import-to={','.join(hidden_imports)}"])
|
11015
|
+
|
11016
|
+
if plugins:
|
11017
|
+
for plugin in plugins:
|
11018
|
+
cmd.extend([f"--plugin-enable={plugin}"])
|
11019
|
+
|
11020
|
+
if additional_args:
|
11021
|
+
cmd.extend(additional_args)
|
11022
|
+
|
11023
|
+
# Add the script path (final positional argument)
|
11024
|
+
cmd.append(str(script_path))
|
11025
|
+
|
11026
|
+
# Ensure Windows shell compatibility
|
11027
|
+
shell_flag = sys.platform.startswith("win")
|
11028
|
+
|
11029
|
+
# Run the command
|
11030
|
+
if verbose:
|
11031
|
+
print(f"Running command: {' '.join(cmd)}")
|
11032
|
+
try:
|
11033
|
+
result = subprocess.run(
|
11034
|
+
cmd,
|
11035
|
+
capture_output=not verbose,
|
11036
|
+
text=True,
|
11037
|
+
shell=shell_flag,
|
11038
|
+
check=True,
|
11039
|
+
)
|
11040
|
+
if verbose:
|
11041
|
+
print(result.stdout)
|
11042
|
+
except subprocess.CalledProcessError as e:
|
11043
|
+
print(f"Error during packaging:\n{e.stderr}", file=sys.stderr)
|
11044
|
+
print(" ".join(cmd))
|
11045
|
+
raise
|
11046
|
+
|
11047
|
+
print("\nPackaging complete. Check the output directory for the executable.")
|
11048
|
+
|
@@ -333,32 +333,6 @@ def parse_cookies(cookies_str):
|
|
333
333
|
|
334
334
|
return cookies_dict
|
335
335
|
|
336
|
-
class FetchSpider(scrapy.Spider):
|
337
|
-
name = "fetch_spider"
|
338
|
-
|
339
|
-
def __init__(self, url, parser="html.parser", cookies=None, headers=None, *args, **kwargs):
|
340
|
-
super(FetchSpider, self).__init__(*args, **kwargs)
|
341
|
-
self.start_urls = [url]
|
342
|
-
self.cookies = cookies
|
343
|
-
self.headers = headers
|
344
|
-
self.parser = parser
|
345
|
-
|
346
|
-
def start_requests(self):
|
347
|
-
for url in self.start_urls:
|
348
|
-
yield scrapy.Request(
|
349
|
-
url,
|
350
|
-
cookies=self.cookies,
|
351
|
-
headers=self.headers,
|
352
|
-
callback=self.parse
|
353
|
-
)
|
354
|
-
|
355
|
-
def parse(self, response):
|
356
|
-
# Use the desired parser (default: html.parser)
|
357
|
-
from bs4 import BeautifulSoup
|
358
|
-
soup = BeautifulSoup(response.text, self.parser)
|
359
|
-
yield {"content": soup}
|
360
|
-
|
361
|
-
|
362
336
|
def fetch_scrapy(
|
363
337
|
url,
|
364
338
|
parser="html.parser",
|
@@ -367,7 +341,7 @@ def fetch_scrapy(
|
|
367
341
|
settings=None,
|
368
342
|
):
|
369
343
|
"""
|
370
|
-
Fetches content using Scrapy.
|
344
|
+
Fetches content using Scrapy with proper reactor handling.
|
371
345
|
|
372
346
|
Args:
|
373
347
|
url (str): The URL to scrape.
|
@@ -380,9 +354,10 @@ def fetch_scrapy(
|
|
380
354
|
dict: Parsed content as a dictionary.
|
381
355
|
"""
|
382
356
|
from scrapy.utils.project import get_project_settings
|
383
|
-
from scrapy.crawler import
|
357
|
+
from scrapy.crawler import CrawlerRunner
|
384
358
|
from scrapy.signalmanager import dispatcher
|
385
359
|
from scrapy import signals
|
360
|
+
from twisted.internet import reactor, defer
|
386
361
|
import scrapy
|
387
362
|
|
388
363
|
# Container for scraped content
|
@@ -403,19 +378,30 @@ def fetch_scrapy(
|
|
403
378
|
}
|
404
379
|
)
|
405
380
|
|
406
|
-
#
|
407
|
-
process = CrawlerProcess(settings=process_settings)
|
381
|
+
# Connect item scraped signal
|
408
382
|
dispatcher.connect(handle_item, signal=signals.item_scraped)
|
409
383
|
|
410
|
-
#
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
384
|
+
# Asynchronous Twisted function
|
385
|
+
@defer.inlineCallbacks
|
386
|
+
def crawl():
|
387
|
+
runner = CrawlerRunner(settings=process_settings)
|
388
|
+
yield runner.crawl(
|
389
|
+
FetchSpider,
|
390
|
+
url=url,
|
391
|
+
parser=parser,
|
392
|
+
cookies=cookies,
|
393
|
+
headers=headers,
|
394
|
+
)
|
395
|
+
reactor.stop()
|
396
|
+
|
397
|
+
# Start the reactor if not already running
|
398
|
+
if not reactor.running:
|
399
|
+
crawl()
|
400
|
+
reactor.run() # Blocks until the crawl finishes
|
401
|
+
else:
|
402
|
+
# Run the crawl if the reactor is already running
|
403
|
+
d = crawl()
|
404
|
+
d.addBoth(lambda _: reactor.stop())
|
419
405
|
|
420
406
|
# Return the first scraped content or None if empty
|
421
407
|
return content[0] if content else None
|
@@ -654,7 +640,11 @@ def fetch_all(
|
|
654
640
|
"COOKIES_ENABLED": True if cookies else False,
|
655
641
|
"LOG_LEVEL": "WARNING", # Reduce log verbosity
|
656
642
|
}
|
657
|
-
content=fetch_scrapy(url,
|
643
|
+
content=fetch_scrapy(url,
|
644
|
+
parser=parser,
|
645
|
+
cookies=cookies,
|
646
|
+
headers=headers,
|
647
|
+
settings=settings)
|
658
648
|
return parser, content
|
659
649
|
|
660
650
|
except requests.RequestException as e:
|