Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
35 changes: 35 additions & 0 deletions CONTRIBUTING.md

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this is a minimal contributing.md partially stolen from #2519. eventually, i'd like to introduce a more reproducible pixi workflow to this repo, then this might also change.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Developing conda-smithy

## Set up Development Environment

To install conda-smithy from source:

* Install `conda`
* Fork and clone this repository: `git clone https://github.com/YOUR-USERNAME/conda-smithy.git`. Change to it: `cd conda-smithy`.
* Create a new conda environment with all requirements based on [environment.yml](environment.yml): `conda env create -f environment.yml`.
* Activate the environment: `conda activate conda-smithy`.
* Install conda-smithy: `pip install --no-deps --editable .`

To run all tests:

```sh
$ pytest
```

To run all code checks:

```sh
# staged changes
$ pre-commit run
# all files
$ pre-commit run --all-files
```

To run pyrefly code checks:

```sh
$ pyrefly check --python-interpreter-path $(which python) --output-format min-text --count-errors=1 --search-path .
```

If you encounter pyrefly issues that you don't agree with, feel free to add a `# pyrefly: ignore[<error-type>]` comment to that line.
Comment on lines +28 to +34

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

as discussed in today's conda/conda-forge meeting with @isuruf.

will add this also to CI once all issues are fixed

Comment thread
pavelzw marked this conversation as resolved.
An ignored `pyrefly` error is insufficient reason to block the merge of a pull request.
6 changes: 1 addition & 5 deletions bootstrap-obvious-ci-and-miniconda.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wouldn't spend too much time on the scripts placed outside conda_smithy and tests. I don't think we using or testing them, which means we are not maintaining them either.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this was all codex, only some tokens were used

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think we using or testing them, which means we are not maintaining them either.

can we just delete them, then?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Probably, but not in this PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

See #2628

Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@
import os
import platform
import subprocess

try:
from urllib.request import urlretrieve
except ImportError:
from urllib import urlretrieve
from urllib.request import urlretrieve

MINICONDA_URL_TEMPLATE = (
"https://repo.continuum.io/miniconda/Miniconda{major_py_version}-"
Expand Down
7 changes: 2 additions & 5 deletions conda_smithy/anaconda_token_rotation.py

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

i updated this change that you had issues with, ptal again @isuruf

Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@ def rotate_anaconda_token(

anaconda_token = _get_anaconda_token()

if github_actions:
gh = Github(gh_token())

# capture stdout, stderr and suppress all exceptions so we don't
# spill tokens
failed = False
Expand Down Expand Up @@ -144,8 +141,7 @@ def rotate_anaconda_token(
raise e
else:
err_msg = (
f"Failed to rotate token for {user}/{project}"
" on azure!"
f"Failed to rotate token for {user}/{project} on azure!"
)
failed = True
raise RuntimeError(err_msg)
Expand All @@ -167,6 +163,7 @@ def rotate_anaconda_token(
raise RuntimeError(err_msg)

if github_actions:
gh = Github(gh_token())
try:
rotate_token_in_github_actions(
user, project, anaconda_token, token_name, gh
Expand Down
4 changes: 2 additions & 2 deletions conda_smithy/ci_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@
class LiveServerSession(requests.Session):
"""Utility class to avoid typing out urls all the time"""

def __init__(self, prefix_url=None, *args, **kwargs):
def __init__(self, prefix_url: str = "", *args, **kwargs):
super().__init__(*args, **kwargs)
self.prefix_url = prefix_url

def request(self, method, url, *args, **kwargs):
def request(self, method, url: str, *args, **kwargs):
from urllib.parse import urljoin

url = urljoin(self.prefix_url, url)
Expand Down
4 changes: 3 additions & 1 deletion conda_smithy/configure_feedstock.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
validate_json_schema,
)

JSONDecodeError = json.JSONDecodeError

conda_forge_content = os.path.abspath(os.path.dirname(__file__))

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -2358,7 +2360,7 @@ def render_readme(jinja_env, forge_config, forge_dir, render_info=None):
"Azure build_id can't be retrieved using the Azure token. Exception: %s",
err,
)
except json.decoder.JSONDecodeError:
except JSONDecodeError:
azure_build_id_from_token(forge_config)

logger.debug("README")
Expand Down
3 changes: 2 additions & 1 deletion conda_smithy/deprecations.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,8 @@ def _generate_message(
raise ValueError(
"'deprecate_in' version needs at least three components"
)
next_version = datetime(*deprecate_in_tuple[:3]) + remove_in
year, month, day = deprecate_in_tuple[:3]
next_version = datetime(year, month, day) + remove_in
remove_in = f"{next_version.year}.{next_version.month}.{next_version.day}"
if self._version_less_than(deprecate_in):
category = PendingDeprecationWarning
Expand Down
10 changes: 5 additions & 5 deletions conda_smithy/feedstock_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ def get_repo(path, search_parent_directories=True):
repo = None
try:
import pygit2
except ImportError:
return None

try:
if search_parent_directories:
path = pygit2.discover_repository(path)
if path is not None:
Expand All @@ -19,19 +22,16 @@ def get_repo(path, search_parent_directories=True):
no_search = pygit2.GIT_REPOSITORY_OPEN_NO_SEARCH

repo = pygit2.Repository(path, no_search)
except ImportError:
pass
except pygit2.GitError:
pass

return repo


def get_repo_root(path):
try:
return get_repo(path).workdir.rstrip(os.path.sep)
except AttributeError:
if (repo := get_repo(path)) is None:
return None
return repo.workdir.rstrip(os.path.sep)


def set_exe_file(filename, set_exe=True):
Expand Down
2 changes: 1 addition & 1 deletion conda_smithy/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ def configure_github_team(
def configure_github_app(
org: str,
repo: str,
app_slug_or_installation_id: str | int = None,
app_slug_or_installation_id: str | int,
remove: bool = False,
) -> None:
"""
Expand Down
7 changes: 3 additions & 4 deletions conda_smithy/linter/hints.py

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

i updated this file that you had issues with @isuruf, ptal again

Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,19 @@ def hint_suggest_noarch(
)
else:
with open(recipe_fname, encoding="utf-8") as fh:
in_runreqs = False
runreqs_spacing = None
no_arch_possible = True
for line in fh:
line_s = line.strip()
if line_s == "host:" or line_s == "run:":
in_runreqs = True
runreqs_spacing = line[: -len(line.lstrip())]
continue
if line_s.startswith("skip:") and is_selector_line(line):
no_arch_possible = False
break
if in_runreqs:
if runreqs_spacing is not None:
if runreqs_spacing == line[: -len(line.lstrip())]:
in_runreqs = False
runreqs_spacing = None
continue
if is_selector_line(line):
no_arch_possible = False
Expand Down
7 changes: 3 additions & 4 deletions conda_smithy/linter/lints.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,11 +327,10 @@ def lint_noarch_and_runtime_dependencies(
return
noarch_platforms = len(forge_yaml.get("noarch_platforms", [])) > 1
with open(meta_fname, encoding="utf-8") as fh:
in_runreqs = False
runreqs_spacing = None
for line_number, line in enumerate(fh, 1):
line_s = line.strip()
if line_s == "host:" or line_s == "run:":
in_runreqs = True
runreqs_spacing = line[: -len(line.lstrip())]
continue
if line_s.startswith("skip:") and is_selector_line(line):
Expand All @@ -344,9 +343,9 @@ def lint_noarch_and_runtime_dependencies(
).as_string()
)
break
if in_runreqs:
if runreqs_spacing is not None:
if runreqs_spacing == line[: -len(line.lstrip())]:
in_runreqs = False
runreqs_spacing = None
continue
if is_selector_line(
line,
Expand Down
4 changes: 3 additions & 1 deletion conda_smithy/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

from __future__ import annotations

from argparse import Namespace

from conda.plugins import hookimpl
from conda.plugins.types import CondaSubcommand


def _execute(args: tuple[str, ...]) -> int | None:
def _execute(args: Namespace | tuple[str, ...]) -> int | None:
"""Dispatch plugin arguments to the smithy CLI.

Lazy import to avoid import-time side effects when not using conda-smithy.
Expand Down
7 changes: 4 additions & 3 deletions conda_smithy/validate_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

class DeprecatedValidator:
def __init__(self):
self.hints = []
self.hints: list[str] = []

def __call__(self, validator, value, instance, schema):
if value and instance is not None:
Expand All @@ -38,8 +38,9 @@ def get_validator_class(deprecated_validator):


def validate_json_schema(
config, schema_file: str = None
) -> tuple[list[ValidationError], list[ValidationError]]:
config,
schema_file: str | Path | None = None,
) -> tuple[list[ValidationError], list[str]]:
# Validate the merged configuration against a JSON schema
if not schema_file:
schema_file = CONDA_FORGE_YAML_SCHEMA_FILE
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies:
- mock
- pytest
- pytest-cov
- pyrefly
# # Part of some optional lint tests
- conda-recipe-manager>=0.9
- conda-souschef
Expand Down
3 changes: 3 additions & 0 deletions news/2593.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Fixed:**

* Fixed several small typing issues reported by Pyrefly. (#2593)
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ include-package-data = true
write_to = "conda_smithy/_version.py"
write_to_template = "__version__ = '{version}'"

[tool.pyrefly]
project-includes = ["conda_smithy/**/*.py", "tests/**/*.py"]
search-path = [".", "tests"]

Comment on lines +34 to +37

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this is needed, otherwise pixi run pyrefly check --python-interpreter-path $(pixi run which python) doesn't show all errors

[tool.black]
# matches black's default value
line-length = 88
Expand Down
14 changes: 6 additions & 8 deletions tests/test_configure_feedstock.py
Original file line number Diff line number Diff line change
Expand Up @@ -1041,9 +1041,8 @@ def load_forge_config(forge_yml):
def test_cos7_env_render(py_recipe, jinja_env):
forge_config = copy.deepcopy(py_recipe.config)
forge_config["os_version"] = {"linux_64": "cos7"}
has_env = "DEFAULT_LINUX_VERSION" in os.environ
if has_env:
old_val = os.environ["DEFAULT_LINUX_VERSION"]
old_val = os.environ.get("DEFAULT_LINUX_VERSION")
if old_val is not None:
del os.environ["DEFAULT_LINUX_VERSION"]

try:
Expand All @@ -1065,7 +1064,7 @@ def test_cos7_env_render(py_recipe, jinja_env):
assert len(os.listdir(matrix_dir)) == 6

finally:
if has_env:
if old_val is not None:
os.environ["DEFAULT_LINUX_VERSION"] = old_val
else:
if "DEFAULT_LINUX_VERSION" in os.environ:
Expand All @@ -1074,9 +1073,8 @@ def test_cos7_env_render(py_recipe, jinja_env):

def test_cuda_enabled_render(cuda_enabled_recipe, jinja_env):
forge_config = copy.deepcopy(cuda_enabled_recipe.config)
has_env = "CF_CUDA_ENABLED" in os.environ
if has_env:
old_val = os.environ["CF_CUDA_ENABLED"]
old_val = os.environ.get("CF_CUDA_ENABLED")
if old_val is not None:
del os.environ["CF_CUDA_ENABLED"]

try:
Expand All @@ -1099,7 +1097,7 @@ def test_cuda_enabled_render(cuda_enabled_recipe, jinja_env):
assert len(os.listdir(matrix_dir)) == 6

finally:
if has_env:
if old_val is not None:
os.environ["CF_CUDA_ENABLED"] = old_val
else:
if "CF_CUDA_ENABLED" in os.environ:
Expand Down
3 changes: 2 additions & 1 deletion tests/test_lint_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import textwrap
import unittest
from collections import OrderedDict
from collections.abc import Iterator
from contextlib import contextmanager
from itertools import count
from pathlib import Path
Expand All @@ -29,7 +30,7 @@


@contextmanager
def get_recipe_in_dir(recipe_name: str) -> Path:
def get_recipe_in_dir(recipe_name: str) -> Iterator[Path]:
base_dir = Path(__file__).parent
recipe_path = base_dir / "recipes" / recipe_name
assert recipe_path.exists(), f"Recipe {recipe_name} does not exist"
Expand Down