initial commit
This commit is contained in:
12
pythonapp/Env/Env.py
Normal file
12
pythonapp/Env/Env.py
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
class Env:
|
||||
def __init__(self):
|
||||
self.pip_path = ""
|
||||
pass
|
||||
|
||||
def create(self):
|
||||
raise NotImplemented
|
||||
|
||||
def install_pkgs(self, pkgs: list, repo: str = None, extra: str = None):
|
||||
raise NotImplemented
|
||||
120
pythonapp/Env/StandaloneEnv.py
Normal file
120
pythonapp/Env/StandaloneEnv.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import urllib.request
|
||||
import zipfile
|
||||
import tarfile
|
||||
import re
|
||||
from typing import List
|
||||
try:
|
||||
from .Env import Env
|
||||
except ImportError:
|
||||
from Env import Env
|
||||
class StandalonePythonEnv(Env):
|
||||
def __init__(self, path: str, version: str):
|
||||
super().__init__()
|
||||
self.version = version
|
||||
self.path = path
|
||||
self.python_path = self._get_python_executable_path()
|
||||
self.pip_path = self._get_pip_executable_path()
|
||||
|
||||
def _get_platform_info(self):
|
||||
system = platform.system().lower()
|
||||
arch = platform.machine().lower()
|
||||
if arch in ['x86_64', 'amd64']:
|
||||
arch = 'amd64'
|
||||
elif arch in ['i386', 'i686', 'x86']:
|
||||
arch = 'win32' if system == 'windows' else 'x86'
|
||||
return system, arch
|
||||
|
||||
def _get_python_executable_path(self):
|
||||
system, _ = self._get_platform_info()
|
||||
if system == 'windows':
|
||||
return os.path.join(self.path, 'python.exe')
|
||||
return os.path.join(self.path, 'bin', 'python3')
|
||||
|
||||
def _get_pip_executable_path(self):
|
||||
system, _ = self._get_platform_info()
|
||||
if system == 'windows':
|
||||
return os.path.join(self.path, 'Scripts', 'pip.exe')
|
||||
return os.path.join(self.path, 'bin', 'pip')
|
||||
|
||||
def _download_and_extract(self):
|
||||
system, arch = self._get_platform_info()
|
||||
base_url = 'https://www.python.org/ftp/python'
|
||||
|
||||
if system == 'windows':
|
||||
url = f'{base_url}/{self.version}/python-{self.version}-embed-{arch}.zip'
|
||||
extract_path = self.path
|
||||
zip_path = os.path.join(self.path, 'python.zip')
|
||||
|
||||
os.makedirs(self.path, exist_ok=True)
|
||||
urllib.request.urlretrieve(url, zip_path)
|
||||
|
||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(extract_path)
|
||||
os.remove(zip_path)
|
||||
|
||||
elif system == 'linux':
|
||||
url = f'{base_url}/{self.version}/Python-{self.version}.tgz'
|
||||
tar_path = os.path.join(self.path, 'python.tgz')
|
||||
|
||||
os.makedirs(self.path, exist_ok=True)
|
||||
urllib.request.urlretrieve(url, tar_path)
|
||||
|
||||
with tarfile.open(tar_path, 'r:gz') as tar_ref:
|
||||
if hasattr(tarfile, 'data_filter'):
|
||||
tar_ref.extractall(self.path, filter='data')
|
||||
else:
|
||||
tar_ref.extractall(self.path)
|
||||
os.remove(tar_path)
|
||||
|
||||
# Компиляция Python из исходников
|
||||
source_dir = os.path.join(self.path, f'Python-{self.version}')
|
||||
subprocess.run([
|
||||
'./configure', f'--prefix={self.path}',
|
||||
'--enable-optimizations',
|
||||
'--with-ensurepip=install'
|
||||
], cwd=source_dir, check=True)
|
||||
subprocess.run(['make', '-j8'], cwd=source_dir, check=True)
|
||||
subprocess.run(['make', 'install'], cwd=source_dir, check=True)
|
||||
|
||||
|
||||
import shutil
|
||||
shutil.copy2(os.path.join(self.path, 'bin', 'pip3'), os.path.join(self.path, 'bin', 'pip'))
|
||||
|
||||
pass
|
||||
|
||||
else:
|
||||
raise NotImplementedError(f"Unsupported platform: {system}")
|
||||
|
||||
def create(self):
|
||||
self._download_and_extract()
|
||||
|
||||
def install_pkgs(self, pkgs: List[str], repo: str = None, extra :str = None):
|
||||
command = [self.pip_path, 'install'] + pkgs
|
||||
if repo: command.extend(["--index-url", repo])
|
||||
if extra: command.extend(["--extra-index-url", extra])
|
||||
subprocess.run(command, check=True)
|
||||
|
||||
@staticmethod
|
||||
def get_available_versions():
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
url = 'https://www.python.org/downloads/'
|
||||
response = requests.get(url)
|
||||
soup = BeautifulSoup(response.text, 'html.parser')
|
||||
|
||||
versions = []
|
||||
for release in soup.select('.release-list .release-number'):
|
||||
version_text = release.text.strip().split()[-1]
|
||||
if re.match(r'^\d+\.\d+\.\d+$', version_text):
|
||||
versions.append(version_text)
|
||||
|
||||
return sorted(versions, key=lambda x: tuple(map(int, x.split('.'))), reverse=True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
env = StandalonePythonEnv(os.path.join('/tmp', 'build/test_standalone'), '3.12.9')
|
||||
env.create()
|
||||
env.install_pkgs(['requests', 'numpy'])
|
||||
45
pythonapp/Env/Venv.py
Normal file
45
pythonapp/Env/Venv.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import subprocess
|
||||
import os
|
||||
from warnings import deprecated
|
||||
|
||||
try:
|
||||
from .Env import Env
|
||||
except ImportError:
|
||||
from Env import Env
|
||||
|
||||
|
||||
class Venv(Env):
|
||||
def __init__(self, path: str, python='python3'):
|
||||
super().__init__()
|
||||
self.path = path
|
||||
self.pip_path = os.path.join(self.path, "bin", "pip")
|
||||
self.python = python
|
||||
self._check_pip()
|
||||
|
||||
def _check_pip(self):
|
||||
if not os.path.exists(self.pip_path): self.pip_path = os.path.join(self.path, "Scripts", "pip")
|
||||
|
||||
def create(self):
|
||||
command = [self.python, '-m', 'venv', self.path]
|
||||
subprocess.run(command)
|
||||
|
||||
def install_pkgs(self, pkgs: list, repo: str = None, extra :str = None):
|
||||
self._check_pip()
|
||||
command: list = [self.pip_path, "install"]
|
||||
command.extend(pkgs)
|
||||
if repo: command.extend(["--index-url", repo])
|
||||
if extra: command.extend(["--extra-index-url", extra])
|
||||
subprocess.run(command, check=True)
|
||||
|
||||
#@deprecated
|
||||
def install_req(self, req_file: str, extra_index_url=None):
|
||||
self._check_pip()
|
||||
command = [self.pip_path, "install", "-r", req_file]
|
||||
if extra_index_url: command.extend(["--extra-index-url", extra_index_url])
|
||||
subprocess.run(command)
|
||||
|
||||
if __name__ == '__main__':
|
||||
env = Venv(os.path.join('/tmp', 'build/test_venv'))
|
||||
env.create()
|
||||
env.install_pkgs(['requests', 'numpy'])
|
||||
|
||||
0
pythonapp/Env/__init__.py
Normal file
0
pythonapp/Env/__init__.py
Normal file
BIN
pythonapp/Env/__pycache__/Env.cpython-313.pyc
Normal file
BIN
pythonapp/Env/__pycache__/Env.cpython-313.pyc
Normal file
Binary file not shown.
BIN
pythonapp/Env/__pycache__/StandaloneEnv.cpython-313.pyc
Normal file
BIN
pythonapp/Env/__pycache__/StandaloneEnv.cpython-313.pyc
Normal file
Binary file not shown.
BIN
pythonapp/Env/__pycache__/Venv.cpython-313.pyc
Normal file
BIN
pythonapp/Env/__pycache__/Venv.cpython-313.pyc
Normal file
Binary file not shown.
BIN
pythonapp/Env/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
pythonapp/Env/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
Reference in New Issue
Block a user