diff --git a/.gitignore b/.gitignore index 324395c..a777acc 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ dist *.egg-info .coverage htmlcov +.dephell_report +docs/build diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4b7e0bd..f233921 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -65,7 +65,7 @@ repos: - id: coverage-badge name: coverage-badge description: create the coverage badge - entry: bash -c "$VIRTUAL_ENV/bin/coverage-badge -f -o docs/img/coverage.svg" + entry: bash -c "$VIRTUAL_ENV/bin/coverage-badge -f -o docs/_static/coverage.svg" language: system types: [python] pass_filenames: false diff --git a/.python-version b/.python-version index c1e43e6..0833a98 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.7.3 +3.7.4 diff --git a/README.md b/README.md index f97fffe..6344ec5 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # conda-env-manager: cenv -![coverage](docs/img/coverage.svg) +![coverage](https://github.com/skallfass/cenv_tool/blob/master/docs/img/coverage.svg) [![PyPI version fury.io](https://badge.fury.io/py/cenv-tool.svg)](https://pypi.python.org/pypi/cenv-tool/) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/cenv-tool.svg)](https://pypi.python.org/pypi/cenv-tool/) [![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/) +[![Documentation Status](https://readthedocs.org/projects/cenv-tool/badge/?version=latest)](https://cenv-tool.readthedocs.io/en/latest/?badge=latest) +[![Powered by DepHell](https://github.com/dephell/dephell/blob/master/assets/badge.svg)](https://github.com/dephell/dephell) -![logo](docs/img/logo.png) +![logo](https://github.com/skallfass/cenv_tool/blob/master/docs/img/logo.png) Due to the redundant dependency information inside the `meta.yaml` (required to create the conda-package) and the `environment.yml` (as definition file @@ -40,14 +42,14 @@ The usage of cenv reduces the conda commands to use to the following: ## Documentation For complete documentation see -[cenv documentation](https://cenv.ouroboros.info/). +[readthedocs](https://cenv-tool.readthedocs.io/en/latest/). ## Installation Install `cenv` using pip: ```bash -pip3 install cenv_tool +pip install cenv_tool ``` Now run `init_cenv` to create the relevant config-files and add the @@ -187,12 +189,30 @@ If you want to turn this functionality on you need to modify your Example for the output of the `cenv` command: +On create: ```bash - ┣━━ Cloning existing env as backup ... - ┣━━ Removing existing env ... - ┣━━ Creating env ... - ┣━━ Removing backup ... - ┗━━ Exporting env to environment.yml ... +Creating cenv_dev + ├── Create environment + │  └── Created + ├── write md5sum of meta.yaml + │  └── updated + └── Done +``` + +On update: +```bash +Updating cenv_dev + ├── Create backup + │  └── Created + ├── Remove existing env + │  └── Removed + ├── Create environment + │  ├── Clear backup + │  │  └── Cleared + │  └── Created + ├── write md5sum of meta.yaml + │  └── updated + └── Done ``` # Development of cenv diff --git a/README.rst b/README.rst index faaee6c..75fa121 100644 --- a/README.rst +++ b/README.rst @@ -3,8 +3,8 @@ conda-env-manager: cenv ======================= -.. image:: docs/img/coverage.svg - :target: docs/img/coverage.svg +.. image:: https://github.com/skallfass/cenv_tool/blob/master/docs/img/coverage.svg + :target: https://github.com/skallfass/cenv_tool/blob/master/docs/img/coverage.svg :alt: coverage @@ -23,9 +23,19 @@ conda-env-manager: cenv :alt: MIT license +.. image:: https://readthedocs.org/projects/cenv-tool/badge/?version=latest + :target: https://cenv-tool.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status -.. image:: docs/img/logo.png - :target: docs/img/logo.png + +.. image:: https://github.com/dephell/dephell/blob/master/assets/badge.svg + :target: https://github.com/dephell/dephell + :alt: Powered by DepHell + + + +.. image:: https://github.com/skallfass/cenv_tool/blob/master/docs/img/logo.png + :target: https://github.com/skallfass/cenv_tool/blob/master/docs/img/logo.png :alt: logo @@ -64,7 +74,7 @@ Documentation ------------- For complete documentation see -`cenv documentation `_. +`readthedocs `_. Installation ------------ @@ -73,7 +83,7 @@ Install ``cenv`` using pip: .. code-block:: bash - pip3 install cenv_tool + pip install cenv_tool Now run ``init_cenv`` to create the relevant config-files and add the autoactivate- and autoupdate-shell-function to your ``.bashrc`` / ``.zshrc``. @@ -229,13 +239,33 @@ If you want to turn this functionality on you need to modify your Example for the output of the ``cenv`` command: +On create: + +.. code-block:: bash + + Creating cenv_dev + ├── Create environment + │  └── Created + ├── write md5sum of meta.yaml + │  └── updated + └── Done + +On update: + .. code-block:: bash - ┣━━ Cloning existing env as backup ... - ┣━━ Removing existing env ... - ┣━━ Creating env ... - ┣━━ Removing backup ... - ┗━━ Exporting env to environment.yml ... + Updating cenv_dev + ├── Create backup + │  └── Created + ├── Remove existing env + │  └── Removed + ├── Create environment + │  ├── Clear backup + │  │  └── Cleared + │  └── Created + ├── write md5sum of meta.yaml + │  └── updated + └── Done Development of cenv =================== diff --git a/cenv_tool/__init__.py b/cenv_tool/__init__.py index c8c3ccc..f43f250 100644 --- a/cenv_tool/__init__.py +++ b/cenv_tool/__init__.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- """Conda environment creation and update from meta.yaml.""" from pkg_resources import get_distribution +from pkg_resources import DistributionNotFound try: __version__ = get_distribution('cenv_tool').version -except AttributeError: +except (AttributeError, DistributionNotFound): __version__ = '' diff --git a/cenv_tool/init_cenv.py b/cenv_tool/init_cenv.py index ed57115..6cc5f1f 100644 --- a/cenv_tool/init_cenv.py +++ b/cenv_tool/init_cenv.py @@ -42,13 +42,13 @@ def initialize_cenv( zshrc: Path, bashrc: Path, ) -> NoReturn: - """Install user-config and cenv.sh for autoactivate and autoupdate. + """ + Install user-config and cenv.sh for autoactivate and autoupdate. Parameters: config_path: the path for cenv config-stuff. autoenv_script_path: the path to install the cenv.sh script to. - autoenv_script_source_path: the path where to get the cenv.sh script - from + autoenv_script_source_path: the path where to get the cenv.sh script from config_file: the path to install the user-config into. config_file_source: the path where to get the config file from. zshrc: the path to the users .zshrc diff --git a/cenv_tool/project.py b/cenv_tool/project.py index af75354..50190db 100644 --- a/cenv_tool/project.py +++ b/cenv_tool/project.py @@ -1,19 +1,20 @@ # -*- coding: utf-8 -*- -"""Contain the processing for creating conda environments from the meta.yaml. +"""Contain the logic for conda environment creation from ``meta.yaml``. -cenv is a tool to handle conda-environment creation and update from the -dependency-definition inside the meta.yaml file. +cenv is a tool to handle conda environment creation and update from the +dependency-definition inside the ``meta.yaml`` file. As default conda has two files for dependency management: -* the environment.yml -* and the meta.yaml +* the ``environment.yml`` +* and the ``meta.yaml`` -In the environment.yml the environment-definition is stored. -In the meta.yaml the required information to build a conda-package are -stored. This means redundant information. +In the ``environment.yml`` the environment-definition is stored. +In the ``meta.yaml`` the required information to build a conda-package are +stored. +This means redundant information. cenv collects the dependency-information and all project-specific settings -from the meta.yaml-file. +from the ``meta.yaml``. The collected information is used to create / update the projects conda environment. @@ -41,11 +42,11 @@ @attr.s(slots=True, auto_attribs=True) class Project: - """Contain a python-project using conda-environments. + """Contain a python-project using conda environments. Containing methods to display information to current project and methods to update the projects conda-environment from the settings defined in the - projects meta.yaml file. + projects ``meta.yaml``. """ rules: Rules @@ -85,13 +86,13 @@ def __attrs_post_init__(self): } def collect_available_envs(self) -> List[str]: - """Collect the names of the conda-environments currently installed. + """Collect the names of the conda environments currently installed. Parameters: conda_folder: the path where conda is installed. Returns: - List of currently installed conda-environments + list of currently installed conda-environments """ return run_in_bash( @@ -100,7 +101,7 @@ def collect_available_envs(self) -> List[str]: ).split('\n') def write_new_md5sum(self): - """Write the new md5sum of the meta.yaml to conda-build/meta.md5.""" + """Write new md5sum of ``meta.yaml`` to ``conda-build/meta.md5``.""" message(text='write md5sum of meta.yaml', color='bold', special='row') command = ( 'echo "$(md5sum $PWD/conda-build/meta.yaml)" | ' @@ -110,13 +111,13 @@ def write_new_md5sum(self): message(text='updated', color='green', special='end', indent=2) def export_environment_definition(self) -> NoReturn: - """Export the projects environment definition to an environment.yml.""" + """Export projects environment definition to an ``environment.yml``.""" message(text='Export environment.yml ...', color='bold', special='row') run_in_bash(cmd=self.cmds.export.format(**self.cmd_kwargs)) message(text='Exported', color='green', special='end', indent=2) def remove_backup_environment(self) -> NoReturn: - """Remove backup cloned from original environment.""" + """Remove backup environment cloned from original environment.""" run_in_bash(cmd=self.cmds.clean.format(**self.cmd_kwargs)) def restore_environment_from_backup(self, cloned: bool) -> NoReturn: @@ -185,10 +186,10 @@ def create_environment(self, cloned: bool) -> NoReturn: """Create the environment for the project. Try to create the environment for the project. If the environment - already existed and a backup was made and any error occurs, the backup - environment is restored. - If everything worked correctly the backup (if made) is finally - removed. + already existed and a backup was made and any error occure, restore the + backup environment. + If everything worked correctly finally remove the backup (if one was + made). Parameters: cloned: indicates if the environment already existed and a backup @@ -201,7 +202,7 @@ def create_environment(self, cloned: bool) -> NoReturn: run_in_bash(cmd=self.cmds.create.format(**self.cmd_kwargs)) except CenvProcessError: self.restore_environment_from_backup(cloned=cloned) - raise + exit(1) if cloned: message(text='Clear backup', color='bold', special='row', indent=2) @@ -211,18 +212,17 @@ def create_environment(self, cloned: bool) -> NoReturn: message(text='Created', color='green', special='end', indent=2) def update(self) -> NoReturn: - """Create / recreate the conda-environment of the current project. + """Create / recreate the conda environment of the current project. - If the conda-environment already exists the user is aked for - confirmation to continue. Then the environment will be cloned as a - backup and the original environment will be removed. Now the new - conda-environment will be created. If a backup was created it is + If the conda environment already exists, clone the environment as a + backup and then remove original environment. Then create the new + conda environment. If a backup was created it is removed afterwards. If any errors occurs during creation of the new - environment the old environment will be recreated from backup and - then the backup will be removed. If activated in the config-file, the - environment-definition of the created environment is exported to an - environment.yml file. Finally the md5sum of the meta.yaml is stored - for the autoupdate feature. + environment, recreate the old environment from backup and remove the + backup afterwards. If activated in the config-file, export the + environment-definition of the created environment to an + ``environment.yml`` file. Finally store the md5sum of the meta.yaml for + the autoupdate feature. """ if self.is_env: message(text=f'Updating {self.env_name}', color='cyan') @@ -241,11 +241,11 @@ def update(self) -> NoReturn: message(text='Done', color='green', special='end') -def build_arguments() -> Namespace: +def build_arguments() -> ArgumentParser: """Create arguments for the cenv-tool. Returns: - The parsed arguments + the parsed arguments. """ parser = ArgumentParser( @@ -260,14 +260,14 @@ def build_arguments() -> Namespace: default=False, help='Show current version of cenv and exit.', ) - args = parser.parse_args() - return args + return parser def main() -> NoReturn: - """Collect the required args, initializing and running the Project.""" - args = build_arguments() - if args.version: + """Collect the required args, initialize and run the Project.""" + parser = build_arguments() + options = parser.parse_args() + if options.version: print(__version__) else: Project(rules=RULES).update() diff --git a/cenv_tool/rules.py b/cenv_tool/rules.py index 2f430f3..968ba8f 100644 --- a/cenv_tool/rules.py +++ b/cenv_tool/rules.py @@ -74,16 +74,33 @@ ) -@attr.s(slots=True) +@attr.s(slots=True, auto_attribs=True) class CondaCmdFormats: - """Contain the formats for the conda commands to use inside cenv.""" + """Contain the formats for the conda commands to use inside cenv. + + Attributes: + remove: command to remove a conda environment. + export: command to use to export a conda environment to an + environment definition file (environment.yml). + create: command to use for conda environment creation. + clone: command to use to clone a conda environment. + restore: command to use to recreate a conda environment from backup + conda environment (clone). + clean: command to use to remove the backup conda environment. + """ - remove = '{conda} remove -n {name} --all -y' - export = '{conda} env export -n {name} > conda-build/environment.yml' - create = '{conda} create -n {name} {pkgs} -y' - clone = '{conda} create -n {name}_backup --clone {name} -y' - restore = '{conda} create -n {name} --clone {name}_backup -y' - clean = '{conda} remove -n {name}_backup --all -y' + remove: str = attr.ib(default='{conda} remove -n {name} --all -y') + export: str = attr.ib( + default='{conda} env export -n {name} > conda-build/environment.yml' + ) + create: str = attr.ib(default='{conda} create -n {name} {pkgs} -y') + clone: str = attr.ib( + default='{conda} create -n {name}_backup --clone {name} -y' + ) + restore: str = attr.ib( + default='{conda} create -n {name} --clone {name}_backup -y' + ) + clean: str = attr.ib(default='{conda} remove -n {name}_backup --all -y') def conda_bin(self, conda_folder): """Combine the path of conda-folder with subpath of conda-bin. @@ -99,8 +116,8 @@ def conda_bin(self, conda_folder): class Rules: """Contain the rules required by cenv-tool.""" - conda_cmds = CondaCmdFormats() - git_folder = '.git' + conda_cmds: CondaCmdFormats = CondaCmdFormats() + git_folder: str = '.git' RULES = Rules() diff --git a/cenv_tool/schemata.py b/cenv_tool/schemata.py index 31d46a3..fd55d13 100644 --- a/cenv_tool/schemata.py +++ b/cenv_tool/schemata.py @@ -6,50 +6,33 @@ class SNPackage(Schema): - """Contain the package-section inside a meta.yaml.""" + """Contain the ``package``-section inside a ``meta.yaml``.""" - name = fields.String( - strict=True, - required=True, - ) - version = fields.String( - strict=True, - required=True, - ) + name = fields.String(strict=True, required=True) + version = fields.String(strict=True, required=True) class SNSource(Schema): - """Contain the source-section inside a meta.yaml.""" + """Contain the ``source``-section inside a ``meta.yaml``.""" - path = fields.String( - strict=True, - required=True, - ) + path = fields.String(strict=True, required=True) class SNBuild(Schema): - """Contain the build-section inside a meta.yaml. + """Contain the ``build``-section inside a ``meta.yaml``. - Schema for the build-section inside a meta.yaml file, to check this section - of a given meta.yaml file in cenv, to be valid. - The build-section requires to define the build-number, if the egg-dir + The ``build``-section requires to define the build-number, if the egg-dir should be preserved, the script to run on installation and if any entrypoints are defined for the package. """ - build = fields.String( - strict=True, - required=True, - ) + build = fields.String(strict=True, required=True) preserve_egg_dir = fields.String( strict=True, required=True, validate=validate.OneOf(['True', 'False']), ) - script = fields.String( - strict=True, - required=True, - ) + script = fields.String(strict=True, required=True) entry_points = fields.List( fields.String(strict=True, required=False), strict=True, @@ -58,18 +41,13 @@ class SNBuild(Schema): class SNRequirements(Schema): - """Contain requirements-section inside a meta.yaml. + """Contain ``requirements``-section inside a ``meta.yaml``. - Schema for the requirements-section inside a meta.yaml file, to check this - section of a given meta.yaml file in cenv, to be valid. - The underlying build- and run-sections have to be valid! + The underlying ``build``- and ``run``-sections have to be valid! """ build = fields.List( - fields.String( - strict=True, - required=True, - ), + fields.String(strict=True, required=True), strict=True, required=True, ) @@ -86,38 +64,26 @@ class SNRequirements(Schema): class SNTest(Schema): - """Contain tests-section inside a meta.yaml. - - Schema for the test-section inside a meta.yaml file, to check this section - of a given meta.yaml file in cenv, to be valid. - """ + """Contain ``tests``-section inside a ``meta.yaml``.""" imports = fields.List( - fields.String( - strict=True, - required=False, - ), + fields.String(strict=True, required=False), strict=True, required=False, ) commands = fields.List( - fields.String( - strict=True, - required=False, - ), + fields.String(strict=True, required=False), strict=True, required=False, ) class SNExtra(Schema): - """Contain the extra-section inside a meta.yaml. + """Contain the ``extra``-section inside a ``meta.yaml``. - Schema for the extra-section inside a meta.yaml file, to check this - section of a given meta.yaml file in cenv, to be valid. - The extra-section has to contains the information where to find the - conda-folder, the name of the conda-environment to use for the current - project and the cenv-version used when the meta.yaml file was created. + The ``extra``-section has to contains the information where to find the + conda-folder, the name of the conda environment to use for the current + project and the cenv-version used when the ``meta.yaml`` file was created. """ env_name = fields.String( @@ -139,41 +105,17 @@ class SNExtra(Schema): class SMetaYaml(Schema): - """Contain the representable of a complete meta.yaml file. + """Contain the representable of a complete ``meta.yaml`` file. - Schema for a meta.yaml file to be used for cenv. - Ensures the meta.yaml to load contains the relevant information about - the package, source, build, requirements and extra. - The test-section is optional. + Schema for a ``meta.yaml`` file to be used for cenv. + Ensure the meta.yaml to load contains the relevant information about + the ``package``, ``source``, ``build``, ``requirements`` and ``extra``. + The ``test``-section is optional. """ - package = fields.Nested( - SNPackage, - strict=True, - required=True, - ) - source = fields.Nested( - SNSource, - strict=True, - required=True, - ) - build = fields.Nested( - SNBuild, - strict=True, - required=True, - ) - requirements = fields.Nested( - SNRequirements, - strict=True, - required=True, - ) - test = fields.Nested( - SNTest, - strict=True, - required=False, - ) - extra = fields.Nested( - SNExtra, - strict=True, - required=True, - ) + package = fields.Nested(SNPackage, strict=True, required=True) + source = fields.Nested(SNSource, strict=True, required=True) + build = fields.Nested(SNBuild, strict=True, required=True) + requirements = fields.Nested(SNRequirements, strict=True, required=True) + test = fields.Nested(SNTest, strict=True, required=False) + extra = fields.Nested(SNExtra, strict=True, required=True) diff --git a/cenv_tool/utils.py b/cenv_tool/utils.py index e10cf7c..19da0bd 100644 --- a/cenv_tool/utils.py +++ b/cenv_tool/utils.py @@ -10,7 +10,7 @@ import jinja2 import six from marshmallow import ValidationError -from ruamel.yaml import YAML +import yaml from cenv_tool.schemata import SMetaYaml @@ -28,10 +28,14 @@ class CenvProcessError(Exception): def message( *, text: str, color: str, special: str = None, indent: int = 1 ) -> NoReturn: - """Print the passed text in the passed color on terminal. + """Print passed ``text`` in the passed ``color`` on terminal. Parameters: - text: The text to print colored on terminal + text: the text to print colored on terminal. + color: the color of the text to print. + special: special kind of message to print. Available are ``'row'`` and + ``'end'``. + indent: the indent to use for the text. """ color_mapping = { @@ -57,7 +61,7 @@ def message( def run_in_bash(cmd: str) -> str: - """Run passed cmd inside bash using the subprocess.check_output-function. + """Run passed ``cmd`` inside bash using :func:`subprocess.check_output`. Parameters: cmd: the command to execute. @@ -68,16 +72,20 @@ def run_in_bash(cmd: str) -> str: """ try: result = check_output([cmd], shell=True, stderr=STDOUT) - except CalledProcessError: - raise CenvProcessError() + except CalledProcessError as err: + error_message = err.output.decode('utf8').split('\n') + message(text='the following error occured:', color='red') + for line in error_message: + message(text=line, color='bold') + raise CenvProcessError(str(err.output)) return result.strip().decode('ascii') class NullUndefined(jinja2.Undefined): - """Handle jinja2-variables with undefined content inside the meta.yaml.""" + """Handle jinja2-variables with undefined content of ``meta.yaml.``""" def __unicode__(self): - """Replace uncode dunder of this class.""" + """Replace unicode dunder of this class.""" return six.text_type(self._undefined_name) def __getattr__(self, attribute_name: str): @@ -90,7 +98,7 @@ def __getitem__(self, attribute_name: str): class StrDict(dict): - """Handle dictionaries for jinja2-variables inside the meta.yaml.""" + """Handle dictionaries for jinja2-variables of ``meta.yaml``.""" def __getitem__(self, key: str, default: str = '') -> str: """Replace getitem dunder of this class.""" @@ -100,17 +108,16 @@ def __getitem__(self, key: str, default: str = '') -> str: def read_meta_yaml(path: Path) -> dict: """Read the meta.yaml file. - The file is read from relative path conda-build/meta.yaml inside - the current path, validates the meta.yaml using the marshmallow-schema, - extracts the dependency-information and the project-settings and returns - these information. + The file is read from relative path ``conda-build/meta.yaml`` inside + the current path, validate the ``meta.yaml`` using the marshmallow-schema, + :class:`SMetaYaml`, extract the dependency-information and the + project-settings and return these information. Parameters: - path: The current working directory + path: the current working directory. Returns: - List containing the project-settings as a dict and the dependencies - also as a dict + list containing the project-settings and the dependencies (both dicts) """ # load the meta.yaml-content @@ -123,7 +130,7 @@ def read_meta_yaml(path: Path) -> dict: 'load_setup_py_data': StrDict, } rendered_myaml = jinja2_loaded_myaml.render(**render_kwargs) - loaded_myaml = YAML(typ='base').load(rendered_myaml) + loaded_myaml = yaml.safe_load(rendered_myaml) # validate the content of loaded meta.yaml try: @@ -139,8 +146,7 @@ def read_meta_yaml(path: Path) -> dict: if meta_yaml_content['extra'].get('dev_requirements'): dependencies.extend(meta_yaml_content['extra']['dev_requirements']) - # combine the collected project-settings and the collected dependencies - # to one output of this function + # return combined collected project-settings and collected dependencies return meta_yaml_content, dependencies @@ -157,11 +163,11 @@ def read_config(): default_config_path = Path(__file__).parent / 'cenv.yml' # Collect settings from config file .cenv.yml - main_config = YAML(typ='safe').load(default_config_path.open().read()) + main_config = yaml.safe_load(default_config_path.open().read()) # if a user-config-file exists, read the content and update the main-config if user_config_path.exists(): - user_config = YAML(typ='safe').load(user_config_path.open().read()) + user_config = yaml.safe_load(user_config_path.open().read()) main_config.update(user_config) return main_config diff --git a/docs/img/coverage.svg b/docs/_static/coverage.svg similarity index 100% rename from docs/img/coverage.svg rename to docs/_static/coverage.svg diff --git a/docs/_static/logo.png b/docs/_static/logo.png new file mode 100644 index 0000000..13037eb Binary files /dev/null and b/docs/_static/logo.png differ diff --git a/docs/about.md b/docs/about.rst similarity index 89% rename from docs/about.md rename to docs/about.rst index f69e513..37c1ab3 100644 --- a/docs/about.md +++ b/docs/about.rst @@ -1,3 +1,6 @@ +About +***** + * **Author**: Simon Kallfass * **Homepage**: https://www.ouroboros.info * **Email**: skallfass@ouroboros.info diff --git a/docs/cenv_tool.rst b/docs/cenv_tool.rst new file mode 100644 index 0000000..5752b61 --- /dev/null +++ b/docs/cenv_tool.rst @@ -0,0 +1,54 @@ +cenv\_tool package +================== + +Submodules +---------- + +cenv\_tool.init\_cenv module +---------------------------- + +.. automodule:: cenv_tool.init_cenv + :members: + :undoc-members: + :show-inheritance: + +cenv\_tool.project module +------------------------- + +.. automodule:: cenv_tool.project + :members: + :undoc-members: + :show-inheritance: + +cenv\_tool.rules module +----------------------- + +.. automodule:: cenv_tool.rules + :members: + :undoc-members: + :show-inheritance: + +cenv\_tool.schemata module +-------------------------- + +.. automodule:: cenv_tool.schemata + :members: + :undoc-members: + :show-inheritance: + +cenv\_tool.utils module +----------------------- + +.. automodule:: cenv_tool.utils + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: cenv_tool + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..3b131fc --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +import sys +import datetime as dt +import pytz +from pathlib import Path + +sys.path.insert(0, str(Path.cwd().parent)) +from cenv_tool import __version__ + + +NOW = dt.datetime.utcnow() +PROJECT_NAME = 'cenv' +HOMEPAGE = 'https://www.ouroboros.info' + + +project = PROJECT_NAME +copyright = f'{NOW.year}, Simon Kallfass' +author = 'Simon Kallfass' +version = __version__ +release = str(NOW.year) +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', + 'sphinx.ext.napoleon', + 'sphinx_autodoc_typehints', +] +templates_path = ['_templates'] +source_suffix = '.rst' +master_doc = 'index' +language = None +exclude_patterns = [] +pygments_style = None + + +html_theme = 'sphinx_rtd_theme' +html_static_path = ['_static'] +htmlhelp_basename = f'{PROJECT_NAME}doc' +html_logo = '_static/logo.png' +html_title = PROJECT_NAME +html_short_title = PROJECT_NAME +html_last_updated_fmt = NOW.replace(tzinfo=pytz.utc).isoformat() +html_show_sourcelink = False + + +html_theme_options = { + 'canonical_url': HOMEPAGE, + 'analytics_id': '', + 'logo_only': False, + 'display_version': True, + 'prev_next_buttons_location': 'bottom', + 'style_external_links': False, + # Toc options + 'collapse_navigation': False, + 'sticky_navigation': True, + 'navigation_depth': 4, + 'includehidden': True, + 'titles_only': False, + 'display_version': True, +} + + +napoleon_include_private_with_doc = True +napoleon_include_special_with_doc = True +napoleon_include_init_with_doc = True +napoleon_use_admonition_for_notes = True +napoleon_use_admonition_for_examples = True +napoleon_use_param = True +napoleon_use_keyword = True +napoleon_use_rtype = False +napoleon_use_ivar = True diff --git a/docs/configuration.md b/docs/configuration.rst similarity index 80% rename from docs/configuration.md rename to docs/configuration.rst index 7dc99ed..ca7caa9 100644 --- a/docs/configuration.md +++ b/docs/configuration.rst @@ -1,14 +1,17 @@ +Configuration +************* + `cenv` uses the path `/opt/conda` as default conda-installation-folder and `/shared/conda/envs` as default conda-environments-folder. You can overwrite these settings with a `cenv.yml` at `~/.config/cenv/cenv.yml` with the following content: -```yaml -conda_folder: /opt/conda -env_folder: /shared/conda/envs -export_environment_yml: false -``` +.. code:: yaml + + conda_folder: /opt/conda + env_folder: /shared/conda/envs + export_environment_yml: false There you can define your own conda-installation-path and the conda-environments-folder. diff --git a/docs/img/logo.png b/docs/img/logo.png deleted file mode 100644 index 9d4447f..0000000 Binary files a/docs/img/logo.png and /dev/null differ diff --git a/docs/impressum.md b/docs/impressum.rst similarity index 92% rename from docs/impressum.md rename to docs/impressum.rst index ea00793..1cb27d8 100644 --- a/docs/impressum.md +++ b/docs/impressum.rst @@ -1,4 +1,8 @@ -## Legal Disclosure +Impressum +********* + +Legal Disclosure +================ Information in accordance with section 5 TMG @@ -7,14 +11,16 @@ Information in accordance with section 5 TMG * 76139 Karlsruhe -## Contact +Contact +------- * Telephone: +49 177 176 7126 * E-Mail: skallfass@ouroboros.info * Homepage: https://www.ouroboros.info -## Disclaimer +Disclaimer +---------- Accountability for content The contents of our pages have been created with the utmost care. However, we @@ -28,7 +34,8 @@ under generally applicable laws remain unaffected by this as per §§ 8 to 10 of the Telemedia Act (TMG). -## Accountability for links +Accountability for links +------------------------ Responsibility for the content of external links (to web pages of third parties) lies solely with the operators of the linked pages. No violations @@ -36,7 +43,8 @@ were evident to us at the time of linking. Should any legal infringement become known to us, we will remove the respective link immediately. -## Copyright +Copyright +--------- Our web pages and their contents are subject to German copyright law. Unless expressly permitted by law (§ 44a et seq. of the copyright law), @@ -48,10 +56,12 @@ Unauthorized utilization of copyrighted works is punishable (§ 106 of the copyright law). -# Privacy Statement +Privacy Statement +================= -## General +General +------- Your personal data (e.g. title, name, house address, e-mail address, phone number, bank details, credit card number) are processed by us only in @@ -62,7 +72,8 @@ web pages. If links on our pages route you to other pages, please inquire there about how your data are handled in such cases. -## Inventory data +Inventory data +-------------- 1. Your personal data, insofar as these are necessary for this contractual relationship (inventory data) in terms of its establishment, organization @@ -77,7 +88,8 @@ there about how your data are handled in such cases. their further use. -## Disclosure +Disclosure +---------- According to the Federal Data Protection Act, you have a right to free-of-charge information about your stored data, and possibly entitlement diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 81eaa96..0000000 --- a/docs/index.md +++ /dev/null @@ -1,39 +0,0 @@ -# conda-env-manager: cenv - -![coverage](img/coverage.svg) -[![PyPI version fury.io](https://badge.fury.io/py/cenv-tool.svg)](https://pypi.python.org/pypi/cenv-tool/) -[![PyPI pyversions](https://img.shields.io/pypi/pyversions/cenv-tool.svg)](https://pypi.python.org/pypi/cenv-tool/) -[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/) - -![logo](img/logo.png) - -Due to the redundant dependency information inside the `meta.yaml` (required -to create the conda-package) and the `environment.yml` (as definition file -for the conda-environment during development and for production), `cenv` -(short form for `conda-env-manager`) was created to make the `meta.yaml` -the only relevant file and to create and update conda-environment from the -definition inside this `meta.yaml`. -The name of the conda-environment to create / update is defined in the section -`extra` and the variable `env_name` inside the `meta.yaml` (at -`conda-build/meta.yaml`). - -The steps run by cenv: - -* creation of a backup if the environment already exists followed by the - removal of the previous environment. -* creation of the environment as defined in the `meta.yaml`. - If any failures occurred during creation and the backup was created, the - command to reset the backup-version can be used. -* if enabled in the config file the environment.yml is exported after creation - / update of the environment. - - -The usage of cenv reduces the conda commands to use to the following: - -* `conda activate ...` to activate the environment -* `conda deactivate` to deactivate an environment -* `conda info` to show information about the currently activated environment -* `conda search ...` to search for availability of a package in the conda - channels. -* `conda remove -n ... --all` to remove an environment -* `cenv` to create / update an environment diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..eacf9d1 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,68 @@ +cenv +**** + +.. image:: _static/coverage.svg + +.. image:: https://badge.fury.io/py/cenv-tool.svg + :target: https://pypi.python.org/pypi/cenv-tool/ + +.. image:: https://img.shields.io/pypi/pyversions/cenv-tool.svg + :target: https://pypi.python.org/pypi/cenv-tool/ + +.. image:: https://img.shields.io/badge/License-MIT-blue.svg + :target: https://lbesson.mit-license.org/ + +.. image:: https://readthedocs.org/projects/cenv-tool/badge/?version=latest + :target: https://cenv-tool.readthedocs.io/en/latest/?badge=latest + + +Tool to create / update conda environments from ``meta.yaml``. + +Due to the redundant dependency information inside the ``meta.yaml`` (required +to create the conda-package) and the ``environment.yml`` (as definition file +for the conda-environment during development and for production), ``cenv`` +(short form for ``conda-env-manager``) was created to make the ``meta.yaml`` +the only relevant file and to create and update conda-environment from the +definition inside this ``meta.yaml``. +The name of the conda-environment to create / update is defined in the section +``extra`` and the variable ``env_name`` inside the ``meta.yaml`` (at +``conda-build/meta.yaml``). + +The steps run by cenv: + + + * creation of a backup if the environment already exists followed by the + removal of the previous environment. + * creation of the environment as defined in the ``meta.yaml``. + If any failures occurred during creation and the backup was created, the + command to reset the backup-version can be used. + * if enabled in the config file the environment.yml is exported after + creation / update of the environment. + + + +The usage of cenv reduces the conda commands to use to the following: + + * ``conda activate ...`` to activate the environment + * ``conda deactivate`` to deactivate an environment + * ``conda info`` to show information about the currently activated + environment + * ``conda search ...`` to search for availability of a package in the conda + channels. + * ``conda remove -n ... --all`` to remove an environment + * ``cenv`` to create / update an environment + + +Table of contents +***************** + +.. toctree:: + :maxdepth: 2 + + installation.rst + configuration.rst + usage.rst + modules_base.rst + about.rst + license.rst + impressum.rst diff --git a/docs/installation.md b/docs/installation.rst similarity index 70% rename from docs/installation.md rename to docs/installation.rst index 09f5747..55564c7 100644 --- a/docs/installation.md +++ b/docs/installation.rst @@ -1,35 +1,45 @@ +Installation +************ + To install cenv simply run: -```bash -pip3 install cenv_tool -``` + +.. code:: bash + + pip install cenv_tool Now run `init_cenv` to create the relevant config-files and add the autoactivate- and autoupdate-shell-function to your `.bashrc` / `.zshrc`. -# autoactivate and autoupdate +autoactivate and autoupdate +=========================== Per default these features are deactivated, even if added to your shell by running `init_cenv`. -## autoactivate-feature +autoactivate-feature +-------------------- The autoactivate-feature activates the conda-environment as named `extra`-section in the meta.yaml located at `conda-build/meta.yaml`, if the environment exists. To activate the autoactivate-features run: -```bash -autoactivate_toggle -``` -## autoupdate-feature +.. code:: bash + + autoactivate_toggle + + +autoupdate-feature +------------------ The autoupdate checks if the content of the meta.yaml changed. The current state is stored as a md5sum in `conda-build/meta.md5`. If it changed the cenv-process is called. For the autoupdate-feature run: -```bash -autoupdate_toggle -``` + +.. code:: bash + + autoupdate_toggle diff --git a/docs/license.md b/docs/license.rst similarity index 98% rename from docs/license.md rename to docs/license.rst index 268f2a9..970f144 100644 --- a/docs/license.md +++ b/docs/license.rst @@ -1,3 +1,6 @@ +License +******* + MIT License Copyright (c) 2019 Simon Kallfass diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 0000000..94ba6f0 --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,7 @@ +cenv_tool +========= + +.. toctree:: + :maxdepth: 4 + + cenv_tool diff --git a/docs/modules_base.rst b/docs/modules_base.rst new file mode 100644 index 0000000..f05a06a --- /dev/null +++ b/docs/modules_base.rst @@ -0,0 +1,7 @@ +Code documentation +****************** + +.. toctree:: + :maxdepth: 4 + + modules.rst diff --git a/docs/usage.md b/docs/usage.md deleted file mode 100644 index 5ac1ff5..0000000 --- a/docs/usage.md +++ /dev/null @@ -1,110 +0,0 @@ -All steps required to create or update the projects conda environment are -run automatically running: -```bash -cenv -``` - -**ATTENTION**: -> If you use cenv, each environment should only be created, updated and -> modified using `cenv`! -> This means the commands `conda install`, `conda remove` are not used -> anymore. -> Changes of the dependencies of the environment are defined inside the -> `meta.yaml` and are applied by using `cenv`. -> -> This means: -> -> * new dependency required => add it in `meta.yaml` and run `cenv`. -> * dependency not needed anymore => remove it from `meta.yaml` and run -> `cenv`. -> * need of another version of dependency => change the version of dependency -> in `meta.yaml` and run `cenv`. - -The required information about the projects conda environment are extracted -from the meta.yaml. -This meta.yaml should be located inside the project folder at -`./conda-build/meta.yaml`. -The project-configuration is defined in the `extra` section of the `meta.yaml`. -There you can define the name of the projects conda-environment at -`env_name`. -Also you can define requirements only needed during development but not to be -included into the resulting conda package. -These requirements have to be defined in the `dev_requirements`-section. - -All other parts of the `meta.yaml` have to be defined as default. - -A meta.yaml valid for cenv should look like the following: -```yaml - {% set data = load_setup_py_data() %} - - package: - name: "example_package" - version: {{ data.get("version") }} - - source: - path: .. - - build: - build: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} - preserve_egg_dir: True - script: python -m pip install --no-deps --ignore-installed . - - requirements: - build: - - python 3.6.8 - - pip - - setuptools - run: - - python 3.6.8 - - attrs >=18.2 - - jinja2 >=2.10 - - ruamel.yaml >=0.15.23 - - six >=1.12.0 - - yaml >=0.1.7 - - marshmallow >=3.0.0rc1* - - test: - imports: - - example_package - - extra: - env_name: example - dev_requirements: - - ipython >=7 -``` - -**ATTENTION**: -> In the `requirements-run-section` the minimal version of each package -> has to be defined! -> The same is required for the `dev_requirements`-section. -> Not defining a version will not create or update a conda-environment, -> because this is not the purpose of the conda-usage. -> The validity of the `meta.yaml` is checked in `cenv` using the -> `marshmallow` package. -> You can additionally add upper limits for the version like the following: -> `- package >=0.1,<0.3` - -If cenv is run the environment is created / updated from the definition inside -this `meta.yaml`. -The creation of the backup of the previous environment ensures to undo changes -if any error occurs during recreation of the environment. - - -**ATTENTION**: -> `cenv` can only update the environment if it is not activated. -> So ensure the environment to be deactivated before running `cenv`. - -Per default exporting the conda environment definition into an environment.yml -is turned off. -If you want to turn this functionality on you need to modify your -`~/.config/cenv.yml` as described in [configuration](configuration.md). - -Example for the output of the `cenv` command: - -```bash - ┣━━ Cloning existing env as backup ... - ┣━━ Removing existing env ... - ┣━━ Creating env ... - ┣━━ Removing backup ... - ┗━━ Exporting env to environment.yml ... -``` diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 0000000..004ed8f --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,165 @@ +Usage +***** + +All steps required to create or update the projects conda environment are +run automatically running ``cenv`` inside the project folder: + + +.. attention:: + If you use cenv, each environment should only be created, updated and + modified using `cenv`! + This means the commands `conda install`, `conda remove` are not used + anymore. + Changes of the dependencies of the environment are defined inside the + `meta.yaml` and are applied by using `cenv`. + + This means: + + * new dependency required => add it in `meta.yaml` and run `cenv`. + * dependency not needed anymore => remove it from `meta.yaml` and run + `cenv`. + * need of another version of dependency => change the version of dependency + in `meta.yaml` and run `cenv`. + + +Project structure +================= + +A project using cenv needs at minimum the following folder structure: + +.. code:: bash + + + ├── conda-build + │  └── meta.yaml + ├── + ├── README.md + └── setup.py + + +meta.yaml +========= + +The required information about the projects conda environment are extracted +from the meta.yaml. +This meta.yaml should be located inside the project folder at +``./conda-build/meta.yaml``. + +The project-configuration is defined in the ``extra`` section of the +``meta.yaml``. +There you can define the name of the projects conda-environment at +``extra:env_name``. +Also you can define requirements only needed during development but not to be +included into the resulting conda package. +These requirements have to be defined in the +``extra:dev_requirements``-section. + +All other parts of the ``meta.yaml`` have to be defined as default. + +A meta.yaml valid for cenv should look like the following: + +.. code:: yaml+jinja + + {% set data = load_setup_py_data() %} + + package: + name: "example_package" + version: {{ data.get("version") }} + + source: + path: .. + + build: + build: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }} + preserve_egg_dir: True + script: python -m pip install --no-deps --ignore-installed . + + requirements: + build: + - python 3.6.8 + - pip + - setuptools + run: + - python 3.6.8 + - attrs >=18.2,<19 + - jinja2 >=2.10 + - six >=1.12.0 + - yaml >=0.1.7 + + test: + imports: + - example_package + + extra: + env_name: example + dev_requirements: + - ipython >=7 + + +.. attention:: + In the ``requirements:run``-section the minimal version of each package + has to be defined like the following: + + .. code:: yaml + + - package >=0.1 + + The same is required for the ``extra:dev_requirements``-section. + Not defining a version will not create or update a conda-environment, + because this is not the purpose of the conda-usage. + The validity of the ``meta.yaml`` is checked in ``cenv`` using the + `marshmallow` package. + You can additionally add upper limits for the version like the following: + + .. code:: yaml + + - package >=0.1,<0.3 + +If cenv is run the environment is created / updated from the definition inside +this ``meta.yaml``. +The creation of the backup of the previous environment ensures to undo changes +if any error occurs during recreation of the environment. + + +.. attention:: + ``cenv`` can only update the environment if it is not activated. + So ensure the environment to be deactivated before running ``cenv``. + +Per default exporting the conda environment definition into an environment.yml +is turned off. +If you want to turn this functionality on you need to modify your +``~/.config/cenv.yml`` as described in `configuration `_. + + +Running cenv +============ + +Example for the output of the ``cenv`` command: + +On create: + +.. code:: bash + + Creating cenv_dev + ├── Create environment + │  └── Created + ├── write md5sum of meta.yaml + │  └── updated + └── Done + +On update: + +.. code:: bash + + Updating cenv_dev + ├── Create backup + │  └── Created + ├── Remove existing env + │  └── Removed + ├── Create environment + │  ├── Clear backup + │  │  └── Cleared + │  └── Created + ├── write md5sum of meta.yaml + │  └── updated + └── Done diff --git a/pyproject.toml b/pyproject.toml index dc5e553..e95fb6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "cenv_tool" -version = "1.0.2" +version = "1.1.0" description = "conda environment creation and update from meta.yaml" license = "MIT" authors = ["Simon Kallfass "] @@ -16,25 +16,26 @@ classifiers = [ [tool.poetry.dependencies] -python = "^3.7" +python = "==3.*,>=3.7.0" attrs = "~19" jinja2 = ">=2" -"ruamel.yaml" = ">=0.15" +pyyaml = "^5" six = ">=1.12" marshmallow = ">=2.19,<3" [tool.poetry.dev-dependencies] -coverage-badge = "~1" +coverage-badge = "==1.*,>=1.0.0" ipython = ">=7" -mkdocs = "~1" monkeytype = ">=19" -pydoc-markdown = "~2" pylint = ">=2" -pytest = "^3.0" -pytest-cov = '~2' -pytest-datafiles = '~2' +pytest = "==5.*,>=5.0.0" +pytest-cov = "==2.*,>=2.0.0" +pytest-datafiles = "==2.*,>=2.0.0" yapf = ">=0" +sphinx = "==2.*,>=2.0.0" +sphinx-autodoc-typehints = "==1.*,>=1.0.0" +sphinx_rtd_theme = "==0.*,>=0.0.0" [tool.poetry.scripts] @@ -42,13 +43,12 @@ cenv = "cenv_tool.project:main" init_cenv = "cenv_tool.init_cenv:main" -[build-system] -requires = ["poetry>=0.12"] -build-backend = "poetry.masonry.api" +[tool.poetry.extras] +docs = ["sphinx", "sphinx-autodoc-typehints"] +tests = ["pytest", "pytest-cov", "pytest-datafiles"] + -[tool.poetry.extras] -docs = ["mkdocs", "pydoc-markdown"] [tool.dephell.main] @@ -70,6 +70,20 @@ to = {format = "poetrylock", path = "poetry.lock"} # read dependencies from poetry format from = {format = "poetry", path = "pyproject.toml"} # install only `docs` extra dependencies -envs = ["docs"] +envs = ["main", "devs", "docs"] # run this command: -command = "mkdocs build" +# command = "mkdocs build" +command = "sphinx-apidoc -f -o docs/source cenv_tool && sphinx-build -W docs/source docs/build" + + +[tool.dephell.pytest] +# read dependencies from setup.py +from = {format = "poetry", path = "pyproject.toml"} +# install main dependencies and `tests` extra dependencies +envs = ["main", "tests"] +tests = ["tests", "cenv_tool", "setup.cfg"] +# run command `pytest` +command = "pytest -c setup.cfg --cache-clear" +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" diff --git a/setup.py b/setup.py index 82c835f..a98db80 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ setup( long_description=readme, name='cenv_tool', - version='1.0.2', + version='1.1.0', description='conda environment creation and update from meta.yaml', python_requires='==3.*,>=3.7.0', project_urls={ @@ -46,15 +46,22 @@ package_data={'cenv_tool': ['*.sh', '*.yml']}, install_requires=[ 'attrs==19.*,>=19.0.0', 'jinja2>=2', 'marshmallow<3,>=2.19', - 'ruamel.yaml>=0.15', 'six>=1.12' + 'pyyaml==5.*,>=5.0.0', 'six>=1.12' ], extras_require={ 'dev': [ - 'coverage-badge==1.*,>=1.0.0', 'ipython>=7', 'mkdocs==1.*,>=1.0.0', - 'monkeytype>=19', 'pydoc-markdown==2.*,>=2.0.0', 'pylint>=2', - 'pytest==3.*,>=3.0.0', 'pytest-cov==2.*,>=2.0.0', - 'pytest-datafiles==2.*,>=2.0.0', 'yapf>=0' + 'coverage-badge==1.*,>=1.0.0', 'ipython>=7', 'monkeytype>=19', + 'pylint>=2', 'pytest==5.*,>=5.0.0', 'pytest-cov==2.*,>=2.0.0', + 'pytest-datafiles==2.*,>=2.0.0', 'sphinx==2.*,>=2.0.0', + 'sphinx-autodoc-typehints==1.*,>=1.0.0', + 'sphinx-rtd-theme==0.*,>=0.0.0', 'yapf>=0' ], - 'docs': ['mkdocs==1.*,>=1.0.0', 'pydoc-markdown==2.*,>=2.0.0'] + 'tests': [ + 'pytest==5.*,>=5.0.0', 'pytest-cov==2.*,>=2.0.0', + 'pytest-datafiles==2.*,>=2.0.0' + ], + 'docs': [ + 'sphinx==2.*,>=2.0.0', 'sphinx-autodoc-typehints==1.*,>=1.0.0' + ] }, ) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/init_cenv_test.py b/tests/init_cenv_test.py index d3072be..5e5e870 100644 --- a/tests/init_cenv_test.py +++ b/tests/init_cenv_test.py @@ -15,13 +15,15 @@ def test_initialize_cenv(datafiles): autoenv_script_path = config_path / 'cenv.sh' zshrc = Path(datafiles) / '.zshrc' bashrc = Path(datafiles) / '.bashrc' + autoenv_script_source_path = Path('cenv_tool/cenv.sh') + config_file_source = Path('cenv_tool/cenv.yml') for _ in range(2): initialize_cenv( config_path=config_path, autoenv_script_path=autoenv_script_path, - autoenv_script_source_path=Path('cenv_tool/cenv.sh'), + autoenv_script_source_path=autoenv_script_source_path, config_file=config_file, - config_file_source=Path('cenv_tool/cenv.yml'), + config_file_source=config_file_source, zshrc=zshrc, bashrc=bashrc, ) diff --git a/tests/missing_meta_yaml/dummy.txt b/tests/missing_meta_yaml/dummy.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/project_test.py b/tests/project_test.py index 91e372f..e101274 100644 --- a/tests/project_test.py +++ b/tests/project_test.py @@ -5,38 +5,73 @@ import pytest from cenv_tool.project import Project +from cenv_tool.project import build_arguments from cenv_tool.rules import RULES def test_project_collect_available_envs(): + """Test if available_envs can be collected.""" current_path = Path.cwd() testfolder = Path('tests/testproject') os.chdir(str(testfolder)) project = Project(rules=RULES) os.chdir(str(current_path)) - available_envs = project.collect_available_envs() - print(available_envs) + assert project.collect_available_envs() @pytest.mark.datafiles('tests/testproject') def test_project_update(datafiles): + """Test the project environment creation, update, backup and cleanup.""" created_env = Path('/shared/conda/envs/cenv_testing_project0001') environment_yml = Path(datafiles) / 'conda-build/environment.yml' current_folder = Path.cwd() + + # test creation of environment os.chdir(datafiles) project = Project(rules=RULES) + assert 'cenv_testing_project0001' not in project.collect_available_envs() + project.update() assert created_env.exists() + assert 'cenv_testing_project0001' in project.collect_available_envs() + + + # test update of environment and the export of the environment.yml project = Project(rules=RULES) + project.export_environment_yml = True project.update() assert created_env.exists() + assert 'cenv_testing_project0001' in project.collect_available_envs() + + + # test remaining methods for project environment project = Project(rules=RULES) project.remove_previous_environment() project.remove_backup_environment() project.create_environment(cloned=False) project.export_environment_definition() assert environment_yml.exists() + + + # clean everything after tests environment_yml.unlink() project.remove_previous_environment() project.remove_backup_environment() os.chdir(str(current_folder)) + + +@pytest.mark.datafiles('tests/missing_meta_yaml') +def test_no_meta_yaml(datafiles): + """Test if exit if no meta.yaml is found.""" + current_folder = Path.cwd() + os.chdir(datafiles) + with pytest.raises(SystemExit): + project = Project(rules=RULES) + os.chdir(str(current_folder)) + + +def test_build_arguments(): + """Test if the option --version is parsable.""" + parser = build_arguments() + options = parser.parse_args(['--v']) + assert options.version diff --git a/tests/testproject/conda-build/meta.yaml b/tests/testproject/conda-build/meta.yaml index 966901d..b2e2778 100644 --- a/tests/testproject/conda-build/meta.yaml +++ b/tests/testproject/conda-build/meta.yaml @@ -34,6 +34,6 @@ test: - cenv_testing_project0001 -v extra: - env_name: cenv_testing_project0001 + env_name: "cenv_testing_project0001" dev_requirements: - pylint >=2.2.2 diff --git a/tests/utils_test.py b/tests/utils_test.py index 8931748..115f4e6 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -8,6 +8,7 @@ from cenv_tool.utils import CenvProcessError from cenv_tool.utils import read_meta_yaml from cenv_tool.utils import run_in_bash +from cenv_tool.utils import StrDict @pytest.mark.parametrize( @@ -93,3 +94,17 @@ def test_run_in_bash_fails(): """Test if run_in_bash works as expected.""" with pytest.raises(CenvProcessError): run_in_bash(cmd='ls-a tests/testproject/conda-build') + + +def test_strdict(): + example_dict = StrDict({ + 'a': 1, + 'b': { + 'c': 'test' + }, + 'd': '' + }) + assert example_dict.get('a') == 1 + assert example_dict.get('b') == {'c': 'test'} + assert not example_dict.get('d') + assert not example_dict.get('e')