2022.6.10 - Dev dependencies #86

Merged
edraft merged 5 commits from 2022.6.10 into 2022.6 2022-06-27 20:18:25 +02:00
15 changed files with 133 additions and 17 deletions

View File

@ -1,10 +1,11 @@
import json import json
import os import os
import shutil
import subprocess import subprocess
import textwrap import textwrap
import time import time
from packaging import version
from cpl_cli.cli_settings import CLISettings from cpl_cli.cli_settings import CLISettings
from cpl_cli.command_abc import CommandABC from cpl_cli.command_abc import CommandABC
from cpl_cli.configuration.build_settings import BuildSettings from cpl_cli.configuration.build_settings import BuildSettings
@ -17,7 +18,6 @@ from cpl_core.console.console import Console
from cpl_core.console.foreground_color_enum import ForegroundColorEnum from cpl_core.console.foreground_color_enum import ForegroundColorEnum
from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC from cpl_core.environment.application_environment_abc import ApplicationEnvironmentABC
from cpl_core.utils.pip import Pip from cpl_core.utils.pip import Pip
from packaging import version
class InstallService(CommandABC): class InstallService(CommandABC):
@ -42,6 +42,7 @@ class InstallService(CommandABC):
self._is_simulation = False self._is_simulation = False
self._is_virtual = False self._is_virtual = False
self._is_dev = False
self._project_file = f'{self._project_settings.name}.json' self._project_file = f'{self._project_settings.name}.json'
@ -82,6 +83,17 @@ class InstallService(CommandABC):
spinner_foreground_color=ForegroundColorEnum.cyan spinner_foreground_color=ForegroundColorEnum.cyan
) )
for dependency in self._project_settings.dev_dependencies:
Console.spinner(
f'Installing dev: {dependency}',
Pip.install if not self._is_virtual else self._wait, dependency if not self._is_virtual else 2,
source=self._cli_settings.pip_path if 'cpl-' in dependency else None,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
text_foreground_color=ForegroundColorEnum.green,
spinner_foreground_color=ForegroundColorEnum.cyan
)
if not self._is_virtual: if not self._is_virtual:
Pip.reset_executable() Pip.reset_executable()
@ -107,7 +119,11 @@ class InstallService(CommandABC):
package_version = package.split('==')[1] package_version = package.split('==')[1]
to_remove_list = [] to_remove_list = []
for dependency in self._project_settings.dependencies: deps = self._project_settings.dependencies
if self._is_dev:
deps = self._project_settings.dev_dependencies
for dependency in deps:
dependency_version = '' dependency_version = ''
if '==' in dependency: if '==' in dependency:
@ -121,6 +137,9 @@ class InstallService(CommandABC):
is_already_in_project = True is_already_in_project = True
for to_remove in to_remove_list: for to_remove in to_remove_list:
if self._is_dev:
self._project_settings.dev_dependencies.remove(to_remove)
else:
self._project_settings.dependencies.remove(to_remove) self._project_settings.dependencies.remove(to_remove)
local_package = Pip.get_package(package) local_package = Pip.get_package(package)
@ -133,9 +152,9 @@ class InstallService(CommandABC):
return return
Console.spinner( Console.spinner(
f'Installing: {package}', f'Installing: {package}' if not self._is_dev else f'Installing dev: {package}',
Pip.install if not self._is_virtual else self._wait, package if not self._is_virtual else 2, Pip.install if not self._is_virtual else self._wait, package if not self._is_virtual else 2,
source=self._cli_settings.pip_path if 'cpl-' in package else None, source=self._cli_settings.pip_path if 'cpl-' in package or 'cpl_' in package else None,
stdout=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
text_foreground_color=ForegroundColorEnum.green, text_foreground_color=ForegroundColorEnum.green,
@ -165,6 +184,9 @@ class InstallService(CommandABC):
if '\r' in new_name: if '\r' in new_name:
new_name = new_name.replace('\r', '') new_name = new_name.replace('\r', '')
if self._is_dev:
self._project_settings.dev_dependencies.append(new_name)
else:
self._project_settings.dependencies.append(new_name) self._project_settings.dependencies.append(new_name)
if not self._is_simulation: if not self._is_simulation:
@ -185,6 +207,10 @@ class InstallService(CommandABC):
:param args: :param args:
:return: :return:
""" """
if 'dev' in args:
self._is_dev = True
args.remove('dev')
if 'virtual' in args: if 'virtual' in args:
self._is_virtual = True self._is_virtual = True
args.remove('virtual') args.remove('virtual')

View File

@ -5,6 +5,7 @@ from typing import Optional
from packaging import version from packaging import version
import cpl_cli
import cpl_core import cpl_core
from cpl_cli.configuration.venv_helper_service import VenvHelper from cpl_cli.configuration.venv_helper_service import VenvHelper
from cpl_cli.source_creator.unittest_builder import UnittestBuilder from cpl_cli.source_creator.unittest_builder import UnittestBuilder
@ -107,6 +108,9 @@ class NewService(CommandABC):
ProjectSettingsNameEnum.dependencies.value: [ ProjectSettingsNameEnum.dependencies.value: [
f'cpl-core>={version.parse(cpl_core.__version__)}' f'cpl-core>={version.parse(cpl_core.__version__)}'
], ],
ProjectSettingsNameEnum.dev_dependencies.value: [
f'cpl-cli>={version.parse(cpl_cli.__version__)}'
],
ProjectSettingsNameEnum.python_version.value: f'>={sys.version.split(" ")[0]}', ProjectSettingsNameEnum.python_version.value: f'>={sys.version.split(" ")[0]}',
ProjectSettingsNameEnum.python_path.value: { ProjectSettingsNameEnum.python_path.value: {
sys.platform: '../../venv/bin/python' if self._use_venv else '' sys.platform: '../../venv/bin/python' if self._use_venv else ''

View File

@ -36,6 +36,8 @@ class UninstallService(CommandABC):
self._is_simulating = False self._is_simulating = False
self._is_virtual = False self._is_virtual = False
self._is_dev = False
self._project_file = f'{self._project_settings.name}.json' self._project_file = f'{self._project_settings.name}.json'
@property @property
@ -62,6 +64,10 @@ class UninstallService(CommandABC):
Console.error(f'Usage: cpl uninstall <package>') Console.error(f'Usage: cpl uninstall <package>')
return return
if 'dev' in args:
self._is_dev = True
args.remove('dev')
if '--virtual' in args: if '--virtual' in args:
self._is_virtual = True self._is_virtual = True
args.remove('--virtual') args.remove('--virtual')
@ -82,7 +88,11 @@ class UninstallService(CommandABC):
else: else:
pip_package = package pip_package = package
for dependency in self._project_settings.dependencies: deps = self._project_settings.dependencies
if self._is_dev:
deps = self._project_settings.dev_dependencies
for dependency in deps:
if package in dependency: if package in dependency:
is_in_dependencies = True is_in_dependencies = True
package = dependency package = dependency
@ -95,7 +105,7 @@ class UninstallService(CommandABC):
package = pip_package package = pip_package
Console.spinner( Console.spinner(
f'Uninstalling: {package}', f'Uninstalling: {package}' if not self._is_dev else f'Uninstalling dev: {package}',
Pip.uninstall if not self._is_virtual else self._wait, package if not self._is_virtual else 2, Pip.uninstall if not self._is_virtual else self._wait, package if not self._is_virtual else 2,
stdout=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
@ -103,8 +113,12 @@ class UninstallService(CommandABC):
spinner_foreground_color=ForegroundColorEnum.cyan spinner_foreground_color=ForegroundColorEnum.cyan
) )
if package in self._project_settings.dependencies: deps = self._project_settings.dependencies
self._project_settings.dependencies.remove(package) if self._is_dev:
deps = self._project_settings.dev_dependencies
if package in deps:
deps.remove(package)
if not self._is_simulating: if not self._is_simulating:
config = { config = {
ProjectSettings.__name__: SettingsHelper.get_project_settings_dict(self._project_settings), ProjectSettings.__name__: SettingsHelper.get_project_settings_dict(self._project_settings),

View File

@ -28,6 +28,7 @@ class ProjectSettings(ConfigurationModelABC):
self._license_name: Optional[str] = None self._license_name: Optional[str] = None
self._license_description: Optional[str] = None self._license_description: Optional[str] = None
self._dependencies: Optional[list[str]] = None self._dependencies: Optional[list[str]] = None
self._dev_dependencies: Optional[list[str]] = None
self._python_version: Optional[str] = None self._python_version: Optional[str] = None
self._python_path: Optional[str] = None self._python_path: Optional[str] = None
self._python_executable: Optional[str] = None self._python_executable: Optional[str] = None
@ -81,6 +82,10 @@ class ProjectSettings(ConfigurationModelABC):
def dependencies(self) -> list[str]: def dependencies(self) -> list[str]:
return self._dependencies return self._dependencies
@property
def dev_dependencies(self) -> list[str]:
return self._dev_dependencies
@property @property
def python_version(self) -> str: def python_version(self) -> str:
return self._python_version return self._python_version
@ -111,6 +116,9 @@ class ProjectSettings(ConfigurationModelABC):
self._license_name = settings[ProjectSettingsNameEnum.license_name.value] self._license_name = settings[ProjectSettingsNameEnum.license_name.value]
self._license_description = settings[ProjectSettingsNameEnum.license_description.value] self._license_description = settings[ProjectSettingsNameEnum.license_description.value]
self._dependencies = settings[ProjectSettingsNameEnum.dependencies.value] self._dependencies = settings[ProjectSettingsNameEnum.dependencies.value]
if ProjectSettingsNameEnum.dev_dependencies.value not in settings:
settings[ProjectSettingsNameEnum.dev_dependencies.value] = []
self._dev_dependencies = settings[ProjectSettingsNameEnum.dev_dependencies.value]
self._python_version = settings[ProjectSettingsNameEnum.python_version.value] self._python_version = settings[ProjectSettingsNameEnum.python_version.value]
self._python_path = settings[ProjectSettingsNameEnum.python_path.value] self._python_path = settings[ProjectSettingsNameEnum.python_path.value]

View File

@ -14,6 +14,7 @@ class ProjectSettingsNameEnum(Enum):
license_name = 'LicenseName' license_name = 'LicenseName'
license_description = 'LicenseDescription' license_description = 'LicenseDescription'
dependencies = 'Dependencies' dependencies = 'Dependencies'
dev_dependencies = 'DevDependencies'
python_version = 'PythonVersion' python_version = 'PythonVersion'
python_path = 'PythonPath' python_path = 'PythonPath'
classifiers = 'Classifiers' classifiers = 'Classifiers'

View File

@ -26,6 +26,7 @@ class SettingsHelper:
ProjectSettingsNameEnum.license_name.value: project.license_name, ProjectSettingsNameEnum.license_name.value: project.license_name,
ProjectSettingsNameEnum.license_description.value: project.license_description, ProjectSettingsNameEnum.license_description.value: project.license_description,
ProjectSettingsNameEnum.dependencies.value: project.dependencies, ProjectSettingsNameEnum.dependencies.value: project.dependencies,
ProjectSettingsNameEnum.dev_dependencies.value: project.dev_dependencies,
ProjectSettingsNameEnum.python_version.value: project.python_version, ProjectSettingsNameEnum.python_version.value: project.python_version,
ProjectSettingsNameEnum.python_path.value: project.python_path, ProjectSettingsNameEnum.python_path.value: project.python_path,
ProjectSettingsNameEnum.classifiers.value: project.classifiers ProjectSettingsNameEnum.classifiers.value: project.classifiers

View File

@ -18,6 +18,7 @@
"Dependencies": [ "Dependencies": [
"cpl-core>=2022.6.17.dev8" "cpl-core>=2022.6.17.dev8"
], ],
"DevDependencies": [],
"PythonVersion": ">=3.10", "PythonVersion": ">=3.10",
"PythonPath": { "PythonPath": {
"linux": "../../venv" "linux": "../../venv"

View File

@ -40,6 +40,7 @@ class StartupArgumentExtension(StartupExtensionABC):
.add_console_argument(ArgumentTypeEnum.Variable, '', 'thread', ['t', 'T'], ' ') \ .add_console_argument(ArgumentTypeEnum.Variable, '', 'thread', ['t', 'T'], ' ') \
.add_console_argument(ArgumentTypeEnum.Variable, '', 'validator', ['v', 'V'], ' ') .add_console_argument(ArgumentTypeEnum.Variable, '', 'validator', ['v', 'V'], ' ')
config.create_console_argument(ArgumentTypeEnum.Executable, '', 'install', ['i', 'I'], InstallService, True, validators=[ProjectValidator]) \ config.create_console_argument(ArgumentTypeEnum.Executable, '', 'install', ['i', 'I'], InstallService, True, validators=[ProjectValidator]) \
.add_console_argument(ArgumentTypeEnum.Flag, '--', 'dev', ['d', 'D']) \
.add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \
.add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S'])
config.create_console_argument(ArgumentTypeEnum.Executable, '', 'new', ['n', 'N'], NewService, True) \ config.create_console_argument(ArgumentTypeEnum.Executable, '', 'new', ['n', 'N'], NewService, True) \
@ -58,6 +59,7 @@ class StartupArgumentExtension(StartupExtensionABC):
config.create_console_argument(ArgumentTypeEnum.Executable, '', 'run', [], RunService, True, validators=[ProjectValidator]) config.create_console_argument(ArgumentTypeEnum.Executable, '', 'run', [], RunService, True, validators=[ProjectValidator])
config.create_console_argument(ArgumentTypeEnum.Executable, '', 'start', ['s', 'S'], StartService, True, validators=[ProjectValidator]) config.create_console_argument(ArgumentTypeEnum.Executable, '', 'start', ['s', 'S'], StartService, True, validators=[ProjectValidator])
config.create_console_argument(ArgumentTypeEnum.Executable, '', 'uninstall', ['ui', 'UI'], UninstallService, True, validators=[ProjectValidator]) \ config.create_console_argument(ArgumentTypeEnum.Executable, '', 'uninstall', ['ui', 'UI'], UninstallService, True, validators=[ProjectValidator]) \
.add_console_argument(ArgumentTypeEnum.Flag, '--', 'dev', ['d', 'D']) \
.add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \ .add_console_argument(ArgumentTypeEnum.Flag, '--', 'virtual', ['v', 'V']) \
.add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S']) .add_console_argument(ArgumentTypeEnum.Flag, '--', 'simulate', ['s', 'S'])
config.create_console_argument(ArgumentTypeEnum.Executable, '', 'update', ['u', 'U'], UpdateService, True, validators=[ProjectValidator]) \ config.create_console_argument(ArgumentTypeEnum.Executable, '', 'update', ['u', 'U'], UpdateService, True, validators=[ProjectValidator]) \

View File

@ -28,6 +28,7 @@
"watchdog==2.1.7", "watchdog==2.1.7",
"wheel==0.37.1" "wheel==0.37.1"
], ],
"DevDependencies": [],
"PythonVersion": ">=3.10", "PythonVersion": ">=3.10",
"PythonPath": {}, "PythonPath": {},
"Classifiers": [] "Classifiers": []

View File

@ -126,7 +126,6 @@ class Pip:
pip_args.append(source) pip_args.append(source)
pip_args.append(package) pip_args.append(package)
print(pip_args)
subprocess.run(pip_args, stdout=stdout, stderr=stderr, env=cls._env) subprocess.run(pip_args, stdout=stdout, stderr=stderr, env=cls._env)
@classmethod @classmethod

View File

@ -16,6 +16,7 @@
"LicenseName": "MIT", "LicenseName": "MIT",
"LicenseDescription": "MIT, see LICENSE for more details.", "LicenseDescription": "MIT, see LICENSE for more details.",
"Dependencies": [], "Dependencies": [],
"DevDependencies": [],
"PythonVersion": ">=3.10", "PythonVersion": ">=3.10",
"PythonPath": {}, "PythonPath": {},
"Classifiers": [] "Classifiers": []

View File

@ -18,6 +18,7 @@
"Dependencies": [ "Dependencies": [
"cpl_core==2022.6.1" "cpl_core==2022.6.1"
], ],
"DevDependencies": [],
"PythonVersion": ">=3.10", "PythonVersion": ">=3.10",
"PythonPath": { "PythonPath": {
"linux": "../../venv/bin/python", "linux": "../../venv/bin/python",

View File

@ -64,6 +64,28 @@ class InstallTestCase(unittest.TestCase):
self.assertIn(package_name, packages) self.assertIn(package_name, packages)
self.assertEqual(version, packages[package_name]) self.assertEqual(version, packages[package_name])
def test_dev_install_package(self):
version = '1.7.3'
package_name = 'discord.py'
package = f'{package_name}=={version}'
CLICommands.install(package, is_dev=True)
settings = self._get_project_settings()
self.assertNotEqual(settings, {})
self.assertIn('ProjectSettings', settings)
self.assertIn('Dependencies', settings['ProjectSettings'])
self.assertIn('DevDependencies', settings['ProjectSettings'])
self.assertNotIn(
package,
settings['ProjectSettings']['Dependencies']
)
self.assertIn(
package,
settings['ProjectSettings']['DevDependencies']
)
packages = self._get_installed_packages()
self.assertIn(package_name, packages)
self.assertEqual(version, packages[package_name])
def _test_install_all(self): def _test_install_all(self):
version = '1.7.3' version = '1.7.3'
package_name = 'discord.py' package_name = 'discord.py'
@ -71,21 +93,33 @@ class InstallTestCase(unittest.TestCase):
settings = self._get_project_settings() settings = self._get_project_settings()
self.assertIn('ProjectSettings', settings) self.assertIn('ProjectSettings', settings)
self.assertIn('Dependencies', settings['ProjectSettings']) self.assertIn('Dependencies', settings['ProjectSettings'])
self.assertIn('DevDependencies', settings['ProjectSettings'])
self.assertNotIn(
package,
settings['ProjectSettings']['Dependencies']
)
self.assertIn('DevDependencies', settings['ProjectSettings'])
self.assertNotIn( self.assertNotIn(
package, package,
settings['ProjectSettings']['Dependencies'] settings['ProjectSettings']['Dependencies']
) )
settings['ProjectSettings']['Dependencies'].append(package) settings['ProjectSettings']['Dependencies'].append(package)
settings['ProjectSettings']['DevDependencies'].append(package)
self._save_project_settings(settings) self._save_project_settings(settings)
CLICommands.install() CLICommands.install()
new_settings = self._get_project_settings() new_settings = self._get_project_settings()
self.assertEqual(settings, new_settings) self.assertEqual(settings, new_settings)
self.assertIn('ProjectSettings', new_settings) self.assertIn('ProjectSettings', new_settings)
self.assertIn('Dependencies', new_settings['ProjectSettings']) self.assertIn('Dependencies', new_settings['ProjectSettings'])
self.assertIn('DevDependencies', new_settings['ProjectSettings'])
self.assertIn( self.assertIn(
package, package,
new_settings['ProjectSettings']['Dependencies'] new_settings['ProjectSettings']['Dependencies']
) )
self.assertIn(
package,
new_settings['ProjectSettings']['DevDependencies']
)
packages = self._get_installed_packages() packages = self._get_installed_packages()
self.assertIn(package_name, packages) self.assertIn(package_name, packages)
self.assertEqual(version, packages[package_name]) self.assertEqual(version, packages[package_name])

View File

@ -33,7 +33,6 @@ class UninstallTestCase(unittest.TestCase):
# create projects # create projects
CLICommands.new('console', self._source, '--ab', '--s') CLICommands.new('console', self._source, '--ab', '--s')
os.chdir(os.path.join(os.getcwd(), self._source)) os.chdir(os.path.join(os.getcwd(), self._source))
CLICommands.install(self._package)
def cleanUp(self): def cleanUp(self):
# remove projects # remove projects
@ -47,6 +46,7 @@ class UninstallTestCase(unittest.TestCase):
return dict([tuple(r.decode().split('==')) for r in reqs.split()]) return dict([tuple(r.decode().split('==')) for r in reqs.split()])
def test_uninstall(self): def test_uninstall(self):
CLICommands.install(self._package)
CLICommands.uninstall(self._package) CLICommands.uninstall(self._package)
settings = self._get_project_settings() settings = self._get_project_settings()
self.assertNotEqual(settings, {}) self.assertNotEqual(settings, {})
@ -56,5 +56,28 @@ class UninstallTestCase(unittest.TestCase):
self._package, self._package,
settings['ProjectSettings']['Dependencies'] settings['ProjectSettings']['Dependencies']
) )
self.assertNotIn(
self._package,
settings['ProjectSettings']['DevDependencies']
)
packages = self._get_installed_packages()
self.assertNotIn(self._package_name, packages)
def test_dev_uninstall(self):
CLICommands.install(self._package, is_dev=True)
CLICommands.uninstall(self._package, is_dev=True)
settings = self._get_project_settings()
self.assertNotEqual(settings, {})
self.assertIn('ProjectSettings', settings)
self.assertIn('Dependencies', settings['ProjectSettings'])
self.assertIn('DevDependencies', settings['ProjectSettings'])
self.assertNotIn(
self._package,
settings['ProjectSettings']['Dependencies']
)
self.assertNotIn(
self._package,
settings['ProjectSettings']['DevDependencies']
)
packages = self._get_installed_packages() packages = self._get_installed_packages()
self.assertNotIn(self._package_name, packages) self.assertNotIn(self._package_name, packages)

View File

@ -44,12 +44,12 @@ class CLICommands:
cls._run('generate', schematic, name, output=output) cls._run('generate', schematic, name, output=output)
@classmethod @classmethod
def install(cls, package: str = None, output=False): def install(cls, package: str = None, is_dev=False, output=False):
if package is None: if package is None:
cls._run('install', output=output) cls._run('install', output=output)
return return
cls._run('install', package, output=output) cls._run('install', package, '--dev' if is_dev else '', output=output)
@classmethod @classmethod
def new(cls, project_type: str, name: str, *args, output=False): def new(cls, project_type: str, name: str, *args, output=False):
@ -75,8 +75,8 @@ class CLICommands:
cls._run('start', output=output) cls._run('start', output=output)
@classmethod @classmethod
def uninstall(cls, package: str, output=False): def uninstall(cls, package: str, is_dev=False, output=False):
cls._run('uninstall', package, output=output) cls._run('uninstall', package, '--dev' if is_dev else '', output=output)
@classmethod @classmethod
def update(cls, output=False): def update(cls, output=False):