Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: deprecate .python key in dependencies; use either .site_package or .pypi #2411

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/userguides/dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,22 @@ dependencies:

When using the `pypi:` key, dependencies are downloaded and extracted from PyPI using an HTTP requests library.

You can also specify the `python:` key for already-installed dependencies:
You can also specify the `site_package:` key for already-installed dependencies:

```yaml
dependencies:
- python: snekmate
- site_package: snekmate
config_override:
contracts_folder: .
```

Using `python:` requires the package to be installed in your `sys.path` (site-packages) folder, generally via `pip` or some other tool.
Using `site_package:` requires the package to be installed in your `sys.path` (site-packages) folder, generally via `pip` or some other tool.
The `contracts_folder` override, in this case, is often needed because the site-package does not have the root source-folder included.
Additionally, `python:` specified dependencies may also be lacking project-configuration files, such as the `ape-config.yaml`.
Additionally, `site_package:` specified dependencies may also be lacking project-configuration files, such as the `ape-config.yaml`.
Compilers such as `vyper` encourage users to use `pip` to publish and install smart-contract dependencies (other vyper files), but some features in Ape may be limited if the dependency is not also specified in your config somewhere.

If wanting to use a dependency from `PyPI`, we recommend using the `pypi:` key instead of the `python:` key.
However, the `python:` key works great if you already used `pip` to install the dependency, especially if the dependency is not available on `PyPI`.
If wanting to use a dependency from `PyPI`, we recommend using the `pypi:` key instead of the `site_package:` key.
However, the `site_package:` key works great if you already used `pip` to install the dependency, especially if the dependency is not available on `PyPI`.

### Local

Expand Down
29 changes: 20 additions & 9 deletions src/ape_pm/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,14 +405,12 @@ def _get_version_from_package_json(
return data.get("version")


# TODO: Rename to `PyPIDependency` in 0.9.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decided not going to do this one either

class PythonDependency(DependencyAPI):
"""
A dependency installed from Python tooling, such as `pip`.
"""

# TODO: Rename this `site_package_name` in 0.9.
python: Optional[str] = None
site_package: Optional[str] = None
"""
The Python site-package name, such as ``"snekmate"``. Cannot use
with ``pypi:``. Requires the dependency to have been installed
Expand All @@ -434,12 +432,20 @@ class PythonDependency(DependencyAPI):
@model_validator(mode="before")
@classmethod
def validate_model(cls, values):
# TODO: In 0.9, remove this check and require 'site_package'.
if "python" in values:
logger.warning(
"'python' key name is deprecated. Use 'site_package' for "
"already-installed packages or 'pypi' to download the package from PyPI."
)
values["site_package"] = values.pop("python")

if "name" not in values:
if name := values.get("python") or values.get("pypi"):
if name := values.get("site_package") or values.get("pypi"):
values["name"] = name
else:
raise ValueError(
"Must set either 'pypi:' or 'python': when using Python dependencies"
"Must set either 'pypi:' or 'site_package': when using Python dependencies"
)

return values
Expand All @@ -450,7 +456,7 @@ def path(self) -> Optional[Path]:
# Is pypi: specified; has no special path.
return None

elif python := self.python:
elif python := self.site_package:
try:
return get_package_path(python)
except ValueError as err:
Expand All @@ -460,11 +466,16 @@ def path(self) -> Optional[Path]:

@property
def package_id(self) -> str:
if pkg_id := (self.pypi or self.python):
if pkg_id := (self.pypi or self.site_package):
return pkg_id

raise ProjectError("Must provide either 'pypi:' or 'python:' for python-base dependencies.")

@property
def python(self) -> str:
logger.warning("'.python' is deprecated. Please use 'site_package'.")
return self.site_package

@property
def version_id(self) -> str:
if self.pypi:
Expand All @@ -473,7 +484,7 @@ def version_id(self) -> str:
# I doubt this is a possible condition, but just in case.
raise ProjectError(f"Missing version from PyPI for package '{self.package_id}'.")

elif self.python:
elif self.site_package:
try:
vers = f"{metadata.version(self.package_id)}"
except metadata.PackageNotFoundError as err:
Expand All @@ -498,7 +509,7 @@ def uri(self) -> str:
if self.pypi:
return self.download_archive_url

elif self.python and (path := self.path):
elif self.site_package and (path := self.path):
# Local site-package path.
return path.as_uri()

Expand Down
4 changes: 2 additions & 2 deletions tests/functional/test_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ def test_fetch_ref(self, mock_client):


class TestPythonDependency:
@pytest.fixture(scope="class", params=("python", "pypi"))
@pytest.fixture(scope="class", params=("site_package", "python", "pypi"))
def python_dependency(self, request):
return PythonDependency.model_validate({request.param: "web3"})

Expand All @@ -613,7 +613,7 @@ def test_version_id(self, python_dependency):

def test_version_id_not_found(self):
name = "xxthisnameisnotarealpythonpackagexx"
dependency = PythonDependency.model_validate({"python": name})
dependency = PythonDependency.model_validate({"site_package": name})
expected = f"Dependency '{name}' not installed."
with pytest.raises(ProjectError, match=expected):
_ = dependency.version_id
Expand Down
Loading