Skip to content

Commit

Permalink
Support different names for base and non-base environment (#180)
Browse files Browse the repository at this point in the history
* Set env_name when not in base environment

* Add note that ENV_NAME will be added to shortcuts outside base environment

* Specify that env_name only gets added on Windows

* Add news

* Remove one set of backtics

* Escape curly braces

* Add PR number to news

* Do not change Windows shortcut name

* Support different names for base and non-base environments

* Change news item to new scope

* Add tests for supporting different names for base and non-base environments

* Make dict typing python 3.8 compatible

* Simplify shortcuts for tests

* Fix Linux shortcut names in test

* Do not allow dicts for menu_name

* Add missing platforms to menu-name.json

* Update docs/source/defining-shortcuts.md

Co-authored-by: Bianca Henderson <beeankha@gmail.com>

* Apply suggestions from code review

Co-authored-by: jaimergp <jaimergp@users.noreply.github.com>

* Make target_environment keywords literals

* Use resolve instead of absolute for prefix comparison

* Use Path.samefile instead of absolute or resolve

* Use TypedDict to represent target_env keys in schema

* Use new model instead of TypedDict for easy python 3.8 compatibility

* Update documentation

* Apply suggestions from code review [skip ci]

Co-authored-by: jaimergp <jaimergp@users.noreply.github.com>

* Use self.env_name as ENV_NAME placeholder

* Use menu prefix

* Use menu base_prefix

* Remove unnecessary sys import

* Set enviornment name to base if prefix equals base_prefix

* Remove or-clause for ENV_NAME placeholder

---------

Co-authored-by: Bianca Henderson <beeankha@gmail.com>
Co-authored-by: jaimergp <jaimergp@users.noreply.github.com>
  • Loading branch information
3 people committed May 8, 2024
1 parent 7da86ea commit 0aa4be1
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 16 deletions.
36 changes: 36 additions & 0 deletions docs/source/defining-shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,42 @@ The full list of available placeholders is available at {ref}`placeholders`.
This is not using any customization options or advanced features. It's the bare minimum to make it
work: a name, the command, and the target platforms.

## Specifying different shortcut names for base and non-base environments

If environments are supported, different naming schemes can be specified for installations into
the base environment and non-base environments.
To do this, the `name` property must be a dictionary with the keys `target_environment_is_base`
and `target_environment_is_not_base` for installations into the base and non-base environment,
respectively.


The example below creates a shortcut called with the name "Launch Turtle" if installed into the
base environment. If installed into an environment called, e.g., `turtle`, the name of the shortcut
is "Launch Turtle (turtle)". This was the default behavior of `menuinst` version 1.

```json
{
"$schema": "https://json-schema.org/draft-07/schema",
"$id": "https://schemas.conda.io/menuinst-1.schema.json",
"menu_name": "Python {{ PY_VER }}",
"menu_items": [
{
"name": {
"target_environment_is_base": "Launch Turtle",
"target_environment_is_not_base": "Launch Turtle ({{ ENV_NAME }})"
}
"command": ["python", "-m", "turtle"],
"activate": true,
"platforms": {
"linux": {},
"osx": {},
"win": {}
}
}
]
}
```

## Associate your shortcut with file types and URL protocols

### File types
Expand Down
1 change: 1 addition & 0 deletions docs/source/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ See Schema below for more details.
```{eval-rst}
.. autopydantic_model:: menuinst._schema.MenuInstSchema
.. autopydantic_model:: menuinst._schema.MenuItem
.. autopydantic_model:: menuinst._schema.MenuItemNameDict
.. autopydantic_model:: menuinst._schema.Platforms
.. autopydantic_model:: menuinst._schema.Linux
.. autopydantic_model:: menuinst._schema.MacOS
Expand Down
27 changes: 23 additions & 4 deletions menuinst/_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ class Config:
extra = "forbid"


class MenuItemNameDict(BaseModel):
"""
Variable menu item name.
Use this dictionary if the menu item name depends on installation parameters
such as the target environment.
"""

target_environment_is_base: Optional[constr(min_length=1)] = None
"Name when target environment is the base environment."
target_environment_is_not_base: Optional[constr(min_length=1)] = None
"Name when target environment is not the base environment."


class BasePlatformSpecific(BaseModel):
"""
Same as :class:`MenuItem`, but without ``platforms``, and all is optional.
Expand All @@ -36,8 +49,11 @@ class BasePlatformSpecific(BaseModel):
* Default value is always ``None``.
"""

name: Optional[constr(min_length=1)] = None
"The name of the menu item"
name: Optional[Union[constr(min_length=1), MenuItemNameDict]] = None
"""
The name of the menu item. Can be a dictionary if the name depends on
installation parameters. See :class:`MenuItemNameDict` for details.
"""
description: Optional[str] = None
"A longer description of the menu item. Shown on popup messages."
icon: Optional[constr(min_length=1)] = None
Expand Down Expand Up @@ -331,8 +347,11 @@ class Platforms(BaseModel):
class MenuItem(BaseModel):
"Instructions to create a menu item across operating systems."

name: constr(min_length=1) = ...
"The name of the menu item."
name: Union[constr(min_length=1), MenuItemNameDict] = ...
"""
The name of the menu item. Can be a dictionary if the name depends on
installation parameters. See :class:`MenuItemNameDict` for details.
"""
description: str = ...
"A longer description of the menu item. Shown on popup messages."
command: conlist(str, min_items=1) = ...
Expand Down
62 changes: 54 additions & 8 deletions menuinst/data/menuinst.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,40 @@
],
"additionalProperties": false,
"definitions": {
"MenuItemNameDict": {
"title": "MenuItemNameDict",
"description": "Variable menu item name.\nUse this dictionary if the menu item name depends on installation parameters\nsuch as the target environment.",
"type": "object",
"properties": {
"target_environment_is_base": {
"title": "Target Environment Is Base",
"minLength": 1,
"type": "string"
},
"target_environment_is_not_base": {
"title": "Target Environment Is Not Base",
"minLength": 1,
"type": "string"
}
},
"additionalProperties": false
},
"Linux": {
"title": "Linux",
"description": "Linux-specific instructions.\n\nCheck the `Desktop entry specification\n<https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#recognized-keys>`__\nfor more details.",
"type": "object",
"properties": {
"name": {
"title": "Name",
"minLength": 1,
"type": "string"
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"$ref": "#/definitions/MenuItemNameDict"
}
]
},
"description": {
"title": "Description",
Expand Down Expand Up @@ -359,8 +384,15 @@
"properties": {
"name": {
"title": "Name",
"minLength": 1,
"type": "string"
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"$ref": "#/definitions/MenuItemNameDict"
}
]
},
"description": {
"title": "Description",
Expand Down Expand Up @@ -517,8 +549,15 @@
"properties": {
"name": {
"title": "Name",
"minLength": 1,
"type": "string"
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"$ref": "#/definitions/MenuItemNameDict"
}
]
},
"description": {
"title": "Description",
Expand Down Expand Up @@ -619,8 +658,15 @@
"properties": {
"name": {
"title": "Name",
"minLength": 1,
"type": "string"
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"$ref": "#/definitions/MenuItemNameDict"
}
]
},
"description": {
"title": "Description",
Expand Down
15 changes: 13 additions & 2 deletions menuinst/platforms/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ def __init__(
self.prefix = Path(prefix)
self.base_prefix = Path(base_prefix)

self.env_name = None
if self.prefix.samefile(self.base_prefix):
self.env_name = "base"
else:
self.env_name = self.prefix.name

def create(self) -> List[Path]:
raise NotImplementedError
Expand Down Expand Up @@ -72,7 +75,7 @@ def placeholders(self) -> Dict[str, str]:
"DISTRIBUTION_NAME": self.base_prefix.name,
"BASE_PYTHON": str(self.base_prefix / "bin" / "python"),
"PREFIX": str(self.prefix),
"ENV_NAME": self.prefix.name,
"ENV_NAME": self.env_name,
"PYTHON": str(self.prefix / "bin" / "python"),
"MENU_DIR": str(self.prefix / "Menu"),
"BIN_DIR": str(self.prefix / "bin"),
Expand Down Expand Up @@ -138,6 +141,14 @@ def __init__(self, menu: Menu, metadata: dict):
self.menu = menu
self._data = self._initialize_on_defaults(metadata)
self.metadata = self._flatten_for_platform(self._data)
if isinstance(self.metadata["name"], dict):
if self.menu.prefix.samefile(self.menu.base_prefix):
name = self.metadata["name"].get("target_environment_is_base", "")
else:
name = self.metadata["name"].get("target_environment_is_not_base", "")
if not name:
raise ValueError("Cannot parse `name` from dictionary representation.")
self.metadata["name"] = name

@property
def location(self) -> Path:
Expand Down
3 changes: 1 addition & 2 deletions menuinst/platforms/win.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,8 @@ def _paths(self) -> Tuple[Path, ...]:
return tuple(paths)

def _shortcut_filename(self, ext: str = "lnk"):
env_suffix = f" ({self.menu.env_name})" if self.menu.env_name else ""
ext = f".{ext}" if ext else ""
return f"{self.render_key('name', extra={})}{env_suffix}{ext}"
return f"{self.render_key('name', extra={})}{ext}"

def _path_for_script(self) -> Path:
return Path(self.menu.placeholders["MENU_DIR"]) / self._shortcut_filename("bat")
Expand Down
19 changes: 19 additions & 0 deletions news/180-support-different-names-outside-base
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
### Enhancements

* Support different name for shortcuts within and outside base environment (support v1 behavior). (#180)

### Bug fixes

* <news item>

### Deprecations

* <news item>

### Docs

* <news item>

### Other

* <news item>
38 changes: 38 additions & 0 deletions tests/data/jsons/menu-name.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "https://json-schema.org/draft-07/schema",
"$id": "https://schemas.conda.io/menuinst-1.schema.json",
"menu_name": "Package",
"menu_items": [
{
"name": {
"target_environment_is_base": "A",
"target_environment_is_not_base": "A_not_in_base"
},
"description": "This will echo environment variables for test purposes",
"icon": null,
"command": [
"echo",
"A"
],
"platforms": {
"win": {},
"linux": {},
"osx": {}
}
},
{
"name": "B",
"description": "This will echo environment variables for test purposes",
"icon": null,
"command": [
"echo",
"B"
],
"platforms": {
"win": {},
"linux": {},
"osx": {}
}
}
]
}
29 changes: 29 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,32 @@ def test_url_protocol_association(delete_files):
url_to_open=url,
expected_output=url,
)


@pytest.mark.parametrize("target_env_is_base", (True, False))
def test_name_dictionary(target_env_is_base):
tmp_base_path = mkdtemp()
tmp_target_path = tmp_base_path if target_env_is_base else mkdtemp()
(Path(tmp_base_path) / ".nonadmin").touch()
if not target_env_is_base:
(Path(tmp_target_path) / ".nonadmin").touch()
abs_json_path = DATA / "jsons" / "menu-name.json"
menu_items = install(abs_json_path, target_prefix=tmp_target_path, base_prefix=tmp_base_path)
try:
if PLATFORM == "linux":
expected = {
"package_a" if target_env_is_base else "package_a-not-in-base",
"package_b",
"package",
}
else:
expected = {
"A" if target_env_is_base else "A_not_in_base",
"B",
}
if PLATFORM == "win":
expected.update(["Package"])
item_names = {item.stem for item in menu_items}
assert item_names == expected
finally:
remove(abs_json_path, target_prefix=tmp_target_path, base_prefix=tmp_base_path)

0 comments on commit 0aa4be1

Please sign in to comment.