Skip to content

Commit

Permalink
Merge pull request #16 from Moo-Ack-Productions/milestone-4-1
Browse files Browse the repository at this point in the history
BpyBuild 0.4.1
  • Loading branch information
StandingPadAnimations authored Jun 4, 2024
2 parents a0741ec + f27fb7f commit 802e924
Show file tree
Hide file tree
Showing 21 changed files with 645 additions and 241 deletions.
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@ repos:
hooks:
# Run the linter.
- id: ruff

# Sort imports
- id: ruff
args: [--select, I, --fix]

# Run the formatter.
- id: ruff-format
103 changes: 103 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,109 @@
# Changelog


## [0.4.1] - 2024-06-01


### Fix: Properly install addon if not already installed

Signed-off-by: Mahid Sheikh <[email protected]>

### Fix: Removed redundant argument in build_config



### Docs: Added details on name and file restrictions

### Docs: Removed tests.md for now

### Docs: Clarified Getting Started

Co-authored-by: Patrick W. Crawford <[email protected]>
### Docs: Added missing period to README

### Docs: Added info on using BpyBuild in addon tests

### Docs: Added info on tests in CONTRIBUTING.md

### Docs: Fixed warning in actions guide



### Feat: Add version shorthands like + and ..

The idea of version shorthands is to reduce the need for comically large
config files with giant lists of versions. Instead of the following:

```yaml
install_versions:
- 2.8
...
- 4.0
```

Developers can now do this:

```yaml
install_versions:
- 2.8..4.0
```

Way better for developer experience

Signed-off-by: Mahid Sheikh <[email protected]>

### Feat: Added string input checks

Seeing as build configs are basically untrusted user input, the current
system of not checking if the strings are valid is a pretty big security
risk. As such, BpyBuild now checks multiple parts of the config to make
sure that strings do not contain harmful characters, by limiting what
characters are allowed in the first place.

### Feat: Improved errors for config issues

### Feat: Added error handling for config parsing

### Feat: Actions can now be declared without a script



### Refactor: Changed how install_versions is checked

Previously we checked install_versions with a try-except statement that
would attempt to convert the value to a float and throw an error if it
failed. However, floats in YAML are actual floats, so we can just check
if the float is of the type float with isinstance(ver, float)

### Refactor: Migrated from cattrs to manual parsing

Although cattrs was useful for parsing the config data to an attrs
object, it had issues with errors being undecipherable to the end user.
In addition, cattrs seemed too overkill for a simple config. Thus, we've
moved away from cattrs and implemented our own basic parser to manually
parse and construct the Config object, with better errors.



### Style: Added docs for BpyError and BpyWarning

### Style: Applied Ruff's import sorter to all files

### Style: Updated codedocs

### Style: Switch to native types with __futures__

### Style: Added TypeDicts for annotation YAML data



### Test: Remove xgettext-replacement test

Signed-off-by: Mahid Sheikh <[email protected]>


<!-- generated by git-cliff -->

## [0.4.0] - 2024-04-18


Expand Down
68 changes: 66 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Contributing Guide
Hey there, looks like you're interested in contributing to Bpy-Build! To get started, read this guide which has a lot of important information regarding contributions.

> [!CAUTION]
> For those that have contributed to MCprep in the past, note that BpyBuild has stricter contributing requirements in comparison.
This guide will assume you already know how to use Git and understand enough Python to know how to use type annotations.

# Building Bpy-Build
Expand All @@ -17,7 +20,7 @@ The Bpy-Build project does not allow dynamic typing at all, period. The reasons
- Reliability: Dynamic typing is an extra source of bugs to deal with
- Cleanliness: Dynamic typing ends up looking extremely ugly

All functions must be type annotated. It is possible to add `@typing.no_type_check` above functions that need to call untyped code (which is considered dynamic by Mypy, the type checker used here) to prevent Mypy from throwing errors with untyped functions. However, instances of `@typing.no_type_check` in contributions will cause said contributions to be rejected. Thus, for contributions, we creating wrappers for untyped functions and performing casts.
All functions must be type annotated. Instances of `@typing.no_type_check` or `# type: ignore` that aren't justified with a comment will cause said contributions to be rejected. Thus, for contributions, we creating wrappers for untyped functions and performing casts.

We require every commit pass Mypy checks, which we utilize pre-commit hooks for (see the Pre-Commit Hooks section for more). Alternatively, you can use the following:
```sh
Expand All @@ -26,6 +29,17 @@ just mypy
# Or if you don't have just installed
poetry run mypy --pretty bpy_addon_build
```

All commits will be checked for passing tests, and PRs will be rejected if one does not pass the Mypy checks.

## Typing
Although BpyBuild supports Python 3.8, we try to use [PEP 585](https://peps.python.org/pep-0585/) types wherever possible, using `annotations` from the `__futures__` module. This means for the most part, `dict`, `list`, `tuple`, etc. can be used with little issue. That being said, the following has to be kept in mind:
- These annotations are hackish in the CPython interpreter, so these can't be used for `attrs`/`cattrs` classes, or if `cast` needs to be performed. In those cases, their `typing` counterparts will have to be used
- New files that use PEP 585 annotations will need to have `from __future__ import annotations` as the first import in the file
- Although it would be nice, [PEP 604](https://peps.python.org/pep-0604/) syntax for Unions is not an option with `__futures__` in Python 3.8

Despite some of the headaches with using annotations from `__futures__`, we encourage their use so that migrating becomes less of a burden in the future.

# Formatting
All commits must be formatted with https://github.com/astral-sh/ruff. We have a pre-commit hook for this (see the Pre-Commit Hooks section).

Expand All @@ -47,7 +61,13 @@ characters long (for reasons related to terminal
length)
```

For a small commit, like say fixing a syntax error or typo, it may be sufficient to have just a summary, but most commits will need justification. Commits should justify the changes made, not repeat them like a parrot (that's what the 50 character summary and Git diffs are for). Failiure to follow proper commit format may prevent a contribution from being accepted into Bpy-Build, so please follow the format.
In addition, the 50 character summary at the top must follow the [Conventional Commit Format](https://www.conventionalcommits.org/en/v1.0.0/).

Commits that fall under the following **ARE REQUIRED** to give justification:
- `feat`
- `refactor`

That being said, it's best to give justification for every commit.

To make meeting this requirement easier, one can make a `.gitmessage` file somewhere with the following :
```
Expand All @@ -70,6 +90,50 @@ git config --local commit.verbose true

This will make all commits use that template and perform verbose commits (where commits are opened as their own file, with saving and closing creating the commit itself).

## Commits MUST *fully commit* to a given change
When a commit is made, the change stated in the commit must be fully committed to. For example, a commit that states `refactor: Use sys.exit method for program exit` **must** implement that change across all files, not just one or two.

## Signing Off Commits
BpyBuild requires signing off of all commits, to certify the origin of the change. When you sign off of a commit in BpyBuild, you certify that the commit was made in line with the Developer's Certificate of Origin:

> Developer's Certificate of Origin 1.1
> By making a contribution to this project, I certify that:
>
> a. The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or \
> b. The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or \
> c. The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. \
> d I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
If indeed the change was made in line with the Developer's Certificate of Origin, add the following at the end of the commit:
```
Signed-off-by: Random J Developer <[email protected]>
```

**This much be your real name and a working email address.**

If the change was given to you by someone else, and you have permission to contribute it here, that change must be signed off by the person who gave the change to you, and anyone before that (basically a chain of sign offs). Example:
```
<commit message and summery by John Doe, who recieved the change from Jane Doe>
Signed-off-by: John Doe <[email protected]>
Signed-off-by: Jane Doe <[email protected]>
```

If multiple authors were involved in writing the change, then `Co-developed-by` must be present for both you and any other authors involved in the change. As an example with 2 authors:
```
<commit message and summery>
Co-developed-by: John Doe <[email protected]>
Signed-off-by: John Doe <[email protected]>
Co-developed-by: Jane Doe <[email protected]>
Signed-off-by: Jane Doe <[email protected]>
```

> [!NOTE]
> *For those interested in where this convention comes from*
>
> Signing off commits was first adopted by the Linux Kernel after [the SCO lawsuits against IBM](https://en.wikipedia.org/wiki/SCO_Group,_Inc._v._International_Business_Machines_Corp.). One of SCO's main arguments was that the Linux Kernel used code from SCO's version of UNIX. Although this turned out to be false, the Linux Kernel project soon required developers to certify that their commits were allowed to be part of the Linux Kernel with signing off.
# Pre-Commit Hooks
To make things easier for developers, we define pre-commit hooks that allow developers to commit changes and automatically have Mypy and Black run on said commit. This is not required
Set up [pre-commit](https://pre-commit.com/). This must be installed separately and is not included in the Poetry dependencies. Then run `pre-commit install`. This will set up pre-commit hooks for the following:
Expand Down
23 changes: 14 additions & 9 deletions bpy_addon_build/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,31 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from typing import Dict, List, Optional, Union
from __future__ import annotations

from decimal import getcontext
from typing import Optional

import yaml
from rich.console import Console

from bpy_addon_build.api import Api
from bpy_addon_build.build_context import hooks
from bpy_addon_build.build_context.build import build
from bpy_addon_build.build_context.install import install
from bpy_addon_build.config import Config, ConfigDict, build_config

from bpy_addon_build.config import Config
from . import args
from .build_context.core import BuildContext
from cattrs.preconf.pyyaml import make_converter
from rich.console import Console


def main() -> None:
# Set the precision for Decimal to
# 3, which corresponds to X.XX
getcontext().prec = 3

cli = args.parse_args()
console = Console()
converter = make_converter()

if cli.debug_mode:
console.print(cli)
Expand All @@ -54,10 +61,8 @@ def main() -> None:

context: Optional[BuildContext] = None
with open(cli.path, "r") as f:
data: Dict[str, Union[str, List[float], Dict[str, Dict[str, str]]]] = (
yaml.safe_load(f)
)
config: Config = converter.structure(data, Config)
data: ConfigDict = yaml.safe_load(f)
config: Config = build_config(data)
api: Api = Api(config, cli.path, cli.debug_mode)
context = BuildContext(cli.path, config, cli, api)

Expand Down
32 changes: 22 additions & 10 deletions bpy_addon_build/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
from types import ModuleType
from typing import Dict, Optional
from __future__ import annotations

import sys
from dataclasses import dataclass
from pathlib import Path
from types import ModuleType
from typing import Optional

from bpy_addon_build.config import Config
from dataclasses import dataclass
import sys


@dataclass
class BpyError:
"""Error object for BpyBuild"""

# Message to print in the console
msg: str


@dataclass
class BpyWarning:
"""Warning object for BpyBuild"""

# Message to print in the console
msg: str


Expand All @@ -30,19 +39,21 @@ class Api:
Attributes
----------
build_actions: Dict[str, str]
build_actions: dict[str, str]
Action name to script file
action_mods: Dict[str, ModuleType]
action_mods: dict[str, ModuleType]
Action name to module
"""

def __init__(self, conf: Config, config_path: Path, debug_mode: bool) -> None:
if conf.build_actions is not None:
self.build_actions = conf.build_actions
self.action_mods: Dict[str, ModuleType] = {}
self.action_mods: dict[str, ModuleType] = {}

for action in self.build_actions:
if self.build_actions[action].script is None:
continue
mod = self.add_modules(config_path, action, debug_mode)
if mod is None:
continue
Expand All @@ -53,9 +64,10 @@ def add_modules(
) -> Optional[ModuleType]:
import importlib.util

path = config_path.parent.resolve().joinpath(
Path(self.build_actions[action].script)
)
script = self.build_actions[action].script
if script is None:
return None
path = config_path.parent.resolve().joinpath(Path(script))

# Add the parent folder of the script to the sys path
# so that we don't get module errors
Expand Down
3 changes: 2 additions & 1 deletion bpy_addon_build/args.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pathlib import Path
from typing import List, Optional, cast
from attrs import define, field, Attribute

from attrs import Attribute, define, field


# Must be ignored to pass Mypy as this has
Expand Down
5 changes: 3 additions & 2 deletions bpy_addon_build/build_context/build.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from bpy_addon_build.build_context.core import BuildContext
from bpy_addon_build.build_context import hooks
import shutil
from pathlib import Path

from bpy_addon_build.build_context import hooks
from bpy_addon_build.build_context.core import BuildContext


def combine_with_build(ctx: BuildContext, path: Path) -> Path:
"""
Expand Down
10 changes: 6 additions & 4 deletions bpy_addon_build/build_context/core.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from __future__ import annotations

from pathlib import Path
from typing import List

from attrs import define
from rich.console import Console

from bpy_addon_build.api import Api
from bpy_addon_build.args import Args

from bpy_addon_build.config import Config
from rich.console import Console

INSTALL_PATHS: List[str] = [
INSTALL_PATHS: list[str] = [
"~/AppData/Roaming/Blender Foundation/Blender/{0}/scripts/addons",
"~/Library/Application Support/Blender/{0}/scripts/addons",
"~/.config/blender/{0}/scripts/addons",
Expand Down
Loading

0 comments on commit 802e924

Please sign in to comment.