Skip to content

Commit 28683de

Browse files
committed
Align builder API better with appose-java
* Rename Builder environment type accessor from name to env_type. * Make various instance fields internal with leading understore. * Use imperative tense for docstrings.
1 parent 17ad626 commit 28683de

File tree

8 files changed

+263
-267
lines changed

8 files changed

+263
-267
lines changed

src/appose/builder/__init__.py

Lines changed: 133 additions & 134 deletions
Large diffs are not rendered by default.

src/appose/builder/mamba.py

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
from . import BaseBuilder, BuildException, Builder, BuilderFactory
3939
from ..environment import Environment
40+
from ..scheme import from_content as scheme_from_content
4041
from ..tool.mamba import Mamba
4142

4243

@@ -47,14 +48,7 @@ class MambaBuilder(BaseBuilder):
4748
Mamba/Micromamba provides fast conda environment management.
4849
"""
4950

50-
def __init__(self):
51-
super().__init__()
52-
53-
# Note: Already assigned in BaseBuilder, but stubgen wants these here, too.
54-
self.source_content: str | None = None
55-
self.scheme: str | None = None
56-
57-
def name(self) -> str:
51+
def env_type(self) -> str:
5852
return "mamba"
5953

6054
def channels(self, *channels: str) -> MambaBuilder:
@@ -67,7 +61,8 @@ def channels(self, *channels: str) -> MambaBuilder:
6761
Returns:
6862
This builder instance
6963
"""
70-
return super().channels(*channels)
64+
super().channels(*channels)
65+
return self
7166

7267
def build(self) -> Environment:
7368
"""
@@ -79,7 +74,7 @@ def build(self) -> Environment:
7974
Raises:
8075
BuildException: If the build fails
8176
"""
82-
env_dir = self._env_dir()
77+
env_dir = self._resolve_env_dir()
8378

8479
# Check for incompatible existing environments
8580
if (env_dir / ".pixi").is_dir():
@@ -103,41 +98,41 @@ def build(self) -> Environment:
10398
return self._create_environment(env_dir, mamba)
10499

105100
# Building a new environment - config content is required
106-
if self.source_content is None:
101+
if self._content is None:
107102
raise BuildException(
108103
self, "No source specified for MambaBuilder. Use .file() or .content()"
109104
)
110105

111106
# Infer scheme if not explicitly set
112-
if self.scheme is None:
113-
self.scheme = self._scheme().name()
107+
if self._scheme is None:
108+
self._scheme = scheme_from_content(self._content)
114109

115-
if self.scheme != "environment.yml":
110+
if self._scheme.name() != "environment.yml":
116111
raise BuildException(
117112
self,
118113
f"MambaBuilder only supports environment.yml scheme, got: {self.scheme}",
119114
)
120115

121116
# Set up progress/output consumers
122117
mamba.set_output_consumer(
123-
lambda msg: [sub(msg) for sub in self.output_subscribers]
118+
lambda msg: [sub(msg) for sub in self._output_subscribers]
124119
)
125120
mamba.set_error_consumer(
126-
lambda msg: [sub(msg) for sub in self.error_subscribers]
121+
lambda msg: [sub(msg) for sub in self._error_subscribers]
127122
)
128123
mamba.set_download_progress_consumer(
129124
lambda cur, max: [
130125
sub("Downloading micromamba", cur, max)
131-
for sub in self.progress_subscribers
126+
for sub in self._progress_subscribers
132127
]
133128
)
134129

135130
# Pass along intended build configuration
136-
mamba.set_env_vars(self.env_vars_dict)
137-
mamba.set_flags(self.flags_list)
131+
mamba.set_env_vars(self._env_vars)
132+
mamba.set_flags(self._flags)
138133

139134
# Check for unsupported features
140-
if self.channels_list:
135+
if self._channels:
141136
raise BuildException(
142137
self,
143138
"MambaBuilder does not yet support programmatic channel configuration. "
@@ -153,7 +148,7 @@ def build(self) -> Environment:
153148

154149
# Step 2: Write environment.yml to envDir
155150
env_yaml = env_dir / "environment.yml"
156-
env_yaml.write_text(self.source_content, encoding="utf-8")
151+
env_yaml.write_text(self._content, encoding="utf-8")
157152

158153
# Step 3: Update environment from yml
159154
mamba.update(env_dir, env_yaml)
@@ -185,7 +180,7 @@ def wrap(self, env_dir: str | Path) -> Environment:
185180
if env_yaml.exists() and env_yaml.is_file():
186181
# Read the content so rebuild() will work even after directory is deleted
187182
with open(env_yaml, "r", encoding="utf-8") as f:
188-
self.source_content = f.read()
183+
self._content = f.read()
189184

190185
# Set the base directory and build (which will detect existing env)
191186
self.base(env_path)
@@ -226,7 +221,7 @@ def create_builder(self) -> Builder:
226221
"""
227222
return MambaBuilder()
228223

229-
def name(self) -> str:
224+
def env_type(self) -> str:
230225
return "mamba"
231226

232227
def supports_scheme(self, scheme: str) -> bool:

src/appose/builder/pixi.py

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
from . import BaseBuilder, BuildException, Builder, BuilderFactory
3838
from ..environment import Environment
39+
from ..scheme import from_content as scheme_from_content
3940
from ..tool.pixi import Pixi
4041

4142

@@ -48,14 +49,10 @@ class PixiBuilder(BaseBuilder):
4849

4950
def __init__(self):
5051
super().__init__()
51-
self.conda_packages: list[str] = []
52-
self.pypi_packages: list[str] = []
52+
self._conda_packages: list[str] = []
53+
self._pypi_packages: list[str] = []
5354

54-
# Note: Already assigned in BaseBuilder, but stubgen wants these here, too.
55-
self.source_content: str | None = None
56-
self.scheme: str | None = None
57-
58-
def name(self) -> str:
55+
def env_type(self) -> str:
5956
return "pixi"
6057

6158
def conda(self, *packages: str) -> PixiBuilder:
@@ -68,7 +65,7 @@ def conda(self, *packages: str) -> PixiBuilder:
6865
Returns:
6966
This builder instance
7067
"""
71-
self.conda_packages.extend(packages)
68+
self._conda_packages.extend(packages)
7269
return self
7370

7471
def pypi(self, *packages: str) -> PixiBuilder:
@@ -81,7 +78,7 @@ def pypi(self, *packages: str) -> PixiBuilder:
8178
Returns:
8279
This builder instance
8380
"""
84-
self.pypi_packages.extend(packages)
81+
self._pypi_packages.extend(packages)
8582
return self
8683

8784
def channels(self, *channels: str) -> PixiBuilder:
@@ -106,7 +103,7 @@ def build(self) -> Environment:
106103
Raises:
107104
BuildException: If the build fails
108105
"""
109-
env_dir = self._env_dir()
106+
env_dir = self._resolve_env_dir()
110107

111108
# Check for incompatible existing environments
112109
if (env_dir / "conda-meta").exists() and not (env_dir / ".pixi").exists():
@@ -124,20 +121,20 @@ def build(self) -> Environment:
124121

125122
# Set up progress/output consumers
126123
pixi.set_output_consumer(
127-
lambda msg: [sub(msg) for sub in self.output_subscribers]
124+
lambda msg: [sub(msg) for sub in self._output_subscribers]
128125
)
129126
pixi.set_error_consumer(
130-
lambda msg: [sub(msg) for sub in self.error_subscribers]
127+
lambda msg: [sub(msg) for sub in self._error_subscribers]
131128
)
132129
pixi.set_download_progress_consumer(
133130
lambda cur, max: [
134-
sub("Downloading pixi", cur, max) for sub in self.progress_subscribers
131+
sub("Downloading pixi", cur, max) for sub in self._progress_subscribers
135132
]
136133
)
137134

138135
# Pass along intended build configuration
139-
pixi.set_env_vars(self.env_vars_dict)
140-
pixi.set_flags(self.flags_list)
136+
pixi.set_env_vars(self._env_vars)
137+
pixi.set_flags(self._flags)
141138

142139
try:
143140
pixi.install()
@@ -151,37 +148,37 @@ def build(self) -> Environment:
151148

152149
if (
153150
is_pixi_dir
154-
and self.source_content is None
155-
and not self.conda_packages
156-
and not self.pypi_packages
151+
and self._content is None
152+
and not self._conda_packages
153+
and not self._pypi_packages
157154
):
158155
# Environment already exists, just use it
159156
return self._create_environment(env_dir, pixi)
160157

161158
# Handle source-based build (file or content)
162-
if self.source_content is not None:
159+
if self._content is not None:
163160
# Infer scheme if not explicitly set
164-
if self.scheme is None:
165-
self.scheme = self._scheme().name()
161+
if self._scheme is None:
162+
self._scheme = scheme_from_content(self._content)
166163

167164
if not env_dir.exists():
168165
env_dir.mkdir(parents=True, exist_ok=True)
169166

170-
if self.scheme == "pixi.toml":
167+
if self._scheme.name() == "pixi.toml":
171168
# Write pixi.toml to envDir
172169
pixi_toml_file = env_dir / "pixi.toml"
173-
pixi_toml_file.write_text(self.source_content, encoding="utf-8")
174-
elif self.scheme == "pyproject.toml":
170+
pixi_toml_file.write_text(self._content, encoding="utf-8")
171+
elif self._scheme.name() == "pyproject.toml":
175172
# Write pyproject.toml to envDir (Pixi natively supports it)
176173
pyproject_toml_file = env_dir / "pyproject.toml"
177174
pyproject_toml_file.write_text(
178-
self.source_content, encoding="utf-8"
175+
self._content, encoding="utf-8"
179176
)
180-
elif self.scheme == "environment.yml":
177+
elif self._scheme.name() == "environment.yml":
181178
# Write environment.yml and import
182179
environment_yaml_file = env_dir / "environment.yml"
183180
environment_yaml_file.write_text(
184-
self.source_content, encoding="utf-8"
181+
self._content, encoding="utf-8"
185182
)
186183
# Only run init --import if pixi.toml doesn't exist yet
187184
# (importing creates pixi.toml, so this avoids "pixi.toml already exists" error)
@@ -194,8 +191,8 @@ def build(self) -> Environment:
194191
)
195192

196193
# Add any programmatic channels to augment source file
197-
if self.channels_list:
198-
pixi.add_channels(env_dir, *self.channels_list)
194+
if self._channels:
195+
pixi.add_channels(env_dir, *self._channels)
199196
else:
200197
# Programmatic package building
201198
if is_pixi_dir:
@@ -208,33 +205,33 @@ def build(self) -> Environment:
208205
pixi.init(env_dir)
209206

210207
# Fail fast for vacuous environments
211-
if not self.conda_packages and not self.pypi_packages:
208+
if not self._conda_packages and not self._pypi_packages:
212209
raise BuildException(
213210
self,
214211
"Cannot build empty environment programmatically. "
215212
"Either provide a source file via Appose.pixi(source), or add packages via .conda() or .pypi().",
216213
)
217214

218215
# Add channels
219-
if self.channels_list:
220-
pixi.add_channels(env_dir, *self.channels_list)
216+
if self._channels:
217+
pixi.add_channels(env_dir, *self._channels)
221218

222219
# Add conda packages
223-
if self.conda_packages:
224-
pixi.add_conda_packages(env_dir, *self.conda_packages)
220+
if self._conda_packages:
221+
pixi.add_conda_packages(env_dir, *self._conda_packages)
225222

226223
# Add PyPI packages
227-
if self.pypi_packages:
228-
pixi.add_pypi_packages(env_dir, *self.pypi_packages)
224+
if self._pypi_packages:
225+
pixi.add_pypi_packages(env_dir, *self._pypi_packages)
229226

230227
# Verify that appose was included when building programmatically
231-
prog_build = bool(self.conda_packages) or bool(self.pypi_packages)
228+
prog_build = bool(self._conda_packages) or bool(self._pypi_packages)
232229
if prog_build:
233230
import re
234231

235232
has_appose = any(
236-
re.match(r"^appose\b", pkg) for pkg in self.conda_packages
237-
) or any(re.match(r"^appose\b", pkg) for pkg in self.pypi_packages)
233+
re.match(r"^appose\b", pkg) for pkg in self._conda_packages
234+
) or any(re.match(r"^appose\b", pkg) for pkg in self._pypi_packages)
238235
if not has_appose:
239236
raise BuildException(
240237
self,
@@ -269,16 +266,16 @@ def wrap(self, env_dir: str | Path) -> Environment:
269266
if pixi_toml.exists() and pixi_toml.is_file():
270267
# Read the content so rebuild() will work even after directory is deleted
271268
with open(pixi_toml, "r", encoding="utf-8") as f:
272-
self.source_content = f.read()
273-
self.scheme = "pixi.toml"
269+
self._content = f.read()
270+
self._scheme = scheme_from_content("pixi.toml")
274271
else:
275272
# Check for pyproject.toml
276273
pyproject_toml = env_path / "pyproject.toml"
277274
if pyproject_toml.exists() and pyproject_toml.is_file():
278275
# Read the content so rebuild() will work even after directory is deleted
279276
with open(pyproject_toml, "r", encoding="utf-8") as f:
280-
self.source_content = f.read()
281-
self.scheme = "pyproject.toml"
277+
self._content = f.read()
278+
self._scheme = scheme_from_content("pyproject.toml")
282279

283280
# Set the base directory and build (which will detect existing env)
284281
self.base(env_path)
@@ -330,7 +327,7 @@ def create_builder(self) -> Builder:
330327
"""
331328
return PixiBuilder()
332329

333-
def name(self) -> str:
330+
def env_type(self) -> str:
334331
return "pixi"
335332

336333
def supports_scheme(self, scheme: str) -> bool:

0 commit comments

Comments
 (0)