Skip to content

project ☄︎

Create project module for scilaunch.

check_booleans_in_cookiecutterrc ☄︎

check_booleans_in_cookiecutterrc()

Check the validity of the .cookiecutterrc file.

Source code in src/scilaunch/project.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def check_booleans_in_cookiecutterrc():
    """Check the validity of the `.cookiecutterrc` file."""
    # Read .cookiecutterrc file (YAML)
    with COOKIECUTTERRC.open() as f:
        cookiecutterrc = yaml.safe_load(f)

    # Read cookiecutter.json file (JSON)
    with Path(path_to.templates.local.cookiecutterrc, "cookiecutter.json").open() as f:
        cookiecutter_json = json.load(f)

    # Check whether the cookiecutterrc file has the correct boolean types
    updated = False
    for key, default_val in cookiecutter_json.items():
        if isinstance(default_val, bool):
            crc_val = cookiecutterrc["default_context"].get(key)
            if isinstance(crc_val, bool):
                continue

            # Overwrite "n" -> False and "y" -> True
            if isinstance(crc_val, str):
                crc_val = _check_str_to_bool(crc_val)
            if isinstance(crc_val, int):
                crc_val = _check_int_to_bool(crc_val)
            if not isinstance(crc_val, bool):
                msg = (
                    f"Invalid type for '{key}': {crc_val} of type {type(crc_val)}."
                    f"\nPlease check '{COOKIECUTTERRC}' and fill with valid boolean value."
                )
                raise TypeError(msg)

            # Set updated boolean default value
            cookiecutterrc["default_context"][key] = default_val if crc_val is None else crc_val
            updated = True

    # Write updated .cookiecutterrc file (YAML)
    if updated:
        print(f"\033[33m\nUpdating {COOKIECUTTERRC} boolean default values ...\033[0m")
        with COOKIECUTTERRC.open("w") as f:
            yaml.dump(cookiecutterrc, f, sort_keys=False, indent=4)

create ☄︎

create(out_dir, create_cc_rc=True, verbose=False, **kwargs)

Create the research project structure based on the research-project template.

Parameters:

Name Type Description Default
out_dir str | pathlib.Path

Path to the output directory.

required
create_cc_rc bool

Whether to create the .cookiecutterrc file.

True
verbose bool

Whether to print verbose output.

False
kwargs dict

Keyword arguments passed to cookiecutter.

{}
Source code in src/scilaunch/project.py
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
def create(out_dir, create_cc_rc=True, verbose=False, **kwargs):
    """
    Create the research project structure based on the `research-project` template.

    :param out_dir: Path to the output directory.
    :type out_dir: str or pathlib.Path
    :param bool create_cc_rc: Whether to create the `.cookiecutterrc` file.
    :param bool verbose: Whether to print verbose output.
    :param dict kwargs: Keyword arguments passed to `cookiecutter`.
    """
    # Create cookiecutterrc file (if not existing)
    if create_cc_rc:
        create_cookiecutterrc(verbose=verbose)

    # Create project
    print(f"\033[34m\nStart creating a new research project structure in {out_dir} ...\n\033[0m")
    template = Path(path_to.templates.local.research_project).expanduser()
    if not template.exists():
        template = path_to.templates.remote.research_project
    else:
        # Check whether the template is up to date
        if verbose:
            print(f"Checking whether '{template.name}' template is up-to-date ...")
        if not is_git_repo_up_to_date(path=template):  # run git fetch
            answer = input(
                f"\033[33m\nYour local version of the '{template.name}' template is not up-to-date.\n"
                f"Do you want to update it now [y/n]: \033[0m"
            )
            if "y" in answer.lower():
                # Run git pull
                _ = Repo(template).remotes.origin.pull()
                print(f"\033[32m\nUpdated local version of the '{template.name}' template.\n\033[0m")
            else:
                print(f"\033[33m\nUsing local version of the '{template.name}' template.\n\033[0m")
        elif verbose:
            print(f"Your local version of the '{template.name}' template seems to be up-to-date.\n")

    # Run cookiecutter on template
    print("\033[4m\033[34m\nProvide information about your research project:\n\033[0m")
    cookiecutter(template=str(template), overwrite_if_exists=False, output_dir=str(out_dir), **kwargs)

create_cookiecutterrc ☄︎

create_cookiecutterrc(verbose=False, **kwargs)

Create the .cookiecutterrc file.

The .cookiecutterrc file is stored in the home directory "~" and contains default values for the research-project template.

Fore more information on the .cookiecutterrc file check out the cookiecutter documentation.

Parameters:

Name Type Description Default
verbose bool

Whether to print verbose output.

False
kwargs dict

Keyword arguments passed to cookiecutter.

{}
Source code in src/scilaunch/project.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def create_cookiecutterrc(verbose=False, **kwargs):
    """
    Create the `.cookiecutterrc` file.

    The `.cookiecutterrc` file is stored in the home directory "`~`"
    and contains default values for the `research-project` template.

    Fore more information on the `.cookiecutterrc` file check out the `cookiecutter`
    [documentation](https://cookiecutter.readthedocs.io/en/stable/index.html).

    :param bool verbose: Whether to print verbose output.
    :param dict kwargs: Keyword arguments passed to `cookiecutter`.
    """
    # Check whether .cookiecutterrc file exists in the home directory
    if not COOKIECUTTERRC.exists():
        # Create cookiecutterrc file
        # Create cache dir
        cache_dir = Path.home() / ".cache/scilaunch"
        cache_dir.mkdir(parents=True, exist_ok=True)

        print(
            f"\033[34m\nSetting default values in {COOKIECUTTERRC} for your new projects. "
            f"This should be done only once ...\n\n"
            f"Note, except for the name and email, recommended defaults are in (*) "
            f"and can be confirmed with just pressing Enter\n\033[0m"
        )
        cookiecutter(template=path_to.templates.local.cookiecutterrc, output_dir=str(cache_dir), **kwargs)

        # Move file to home directory
        # Read cache dir from json
        with Path(path_to.templates.local.cookiecutterrc, "cookiecutter.json").open() as f:
            cache_dir = cache_dir / json.load(f).get("_cache_dir")
        (cache_dir / COOKIECUTTERRC.name).rename(COOKIECUTTERRC)

        # Remove cache dir
        cache_dir.rmdir()

        # Report
        print(f"\033[32m\nCreated {COOKIECUTTERRC}\n\033[0m")

        # Print content
        with COOKIECUTTERRC.open() as f:
            print(f.read())

        print(
            f"\033[33m\nIf you want to revise your defaults settings at a later stage, "
            f"just edit the file: {COOKIECUTTERRC}.\n\033[0m"
        )

    else:
        check_booleans_in_cookiecutterrc()
        if verbose:
            print(f"\nUsing existing {COOKIECUTTERRC} to fill defaults.\n")

is_git_repo_up_to_date ☄︎

is_git_repo_up_to_date(path)

Check whether the local git repository at the given path is up to date.

Parameters:

Name Type Description Default
path str | pathlib.Path

Path to the local git repository.

required

Returns:

Type Description
bool

True if the local git repository is up to date, False otherwise.

Source code in src/scilaunch/project.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
def is_git_repo_up_to_date(path):
    """
    Check whether the local git repository at the given path is up to date.

    :param path: Path to the local git repository.
    :type path: str or pathlib.Path
    :return: True if the local git repository is up to date, False otherwise.
    :rtype: bool
    """
    repo = Repo(path)
    upstream = repo.remotes.origin
    try:
        upstream.fetch(kill_after_timeout=10)  # run git fetch to update the remote-tracking branches
    except GitCommandError as e:
        additional_err_msg = (
            "\033[31mUnable to fetch data from remote repository! Check your internet connection!\033[0m"
        )
        raise GitCommandError(str(e) + additional_err_msg) from e
    return repo.head.commit == upstream.refs.main.commit