Skip to content

Commit 7dad053

Browse files
authored
add input validation to PkgSpec (#59)
* feat: add input validation to PkgSpec * use Union for old python compat * update changelog --------- Co-authored-by: Christopher Doris <github.com/cjdoris>
1 parent 3c66a04 commit 7dad053

File tree

3 files changed

+111
-8
lines changed

3 files changed

+111
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44
* Support editable dependencies from setuptools (experimental).
5+
* Better input validation.
56

67
## v0.1.17 (2025-05-13)
78
* Respect `JULIAUP_DEPOT_PATH` when searching for Julia using juliaup.

src/juliapkg/deps.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import sys
66
from subprocess import run
7+
from typing import Union
78

89
from filelock import FileLock
910

@@ -50,22 +51,53 @@ def save_meta(meta):
5051
class PkgSpec:
5152
def __init__(
5253
self,
53-
name,
54-
uuid,
55-
dev=False,
56-
version=None,
57-
path=None,
58-
subdir=None,
59-
url=None,
60-
rev=None,
54+
name: str,
55+
uuid: str,
56+
dev: bool = False,
57+
version: Union[str, Version, None] = None,
58+
path: Union[str, None] = None,
59+
subdir: Union[str, None] = None,
60+
url: Union[str, None] = None,
61+
rev: Union[str, None] = None,
6162
):
63+
# Validate name (non-empty string)
64+
if not isinstance(name, str) or not name.strip():
65+
raise ValueError("name must be a non-empty string")
6266
self.name = name
67+
68+
# Validate UUID (non-empty string, could add more specific UUID validation)
69+
if not isinstance(uuid, str) or not uuid.strip():
70+
raise ValueError("uuid must be a non-empty string")
6371
self.uuid = uuid
72+
73+
# Validate dev (boolean)
74+
if not isinstance(dev, bool):
75+
raise TypeError("dev must be a boolean")
6476
self.dev = dev
77+
78+
# Validate version (string, Version, or None)
79+
if version is not None and not isinstance(version, (str, Version)):
80+
raise TypeError("version must be a string, Version, or None")
6581
self.version = version
82+
83+
# Validate path (string or None)
84+
if path is not None and not isinstance(path, str):
85+
raise TypeError("path must be a string or None")
6686
self.path = path
87+
88+
# Validate subdir (string or None)
89+
if subdir is not None and not isinstance(subdir, str):
90+
raise TypeError("subdir must be a string or None")
6791
self.subdir = subdir
92+
93+
# Validate url (string or None)
94+
if url is not None and not isinstance(url, str):
95+
raise TypeError("url must be a string or None")
6896
self.url = url
97+
98+
# Validate rev (string or None)
99+
if rev is not None and not isinstance(rev, str):
100+
raise TypeError("rev must be a string or None")
69101
self.rev = rev
70102

71103
def jlstr(self):

test/test_internals.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import pytest
2+
13
import juliapkg
4+
from juliapkg.deps import PkgSpec
25

36

47
def test_openssl_compat():
@@ -8,3 +11,70 @@ def test_openssl_compat():
811
assert juliapkg.deps.openssl_compat((3, 1, 0)) == "3 - 3.1"
912
assert juliapkg.deps.openssl_compat((3, 1, 2)) == "3 - 3.1"
1013
assert isinstance(juliapkg.deps.openssl_compat(), str)
14+
15+
16+
def test_pkgspec_validation():
17+
# Test valid construction
18+
spec = PkgSpec(name="Example", uuid="123e4567-e89b-12d3-a456-426614174000")
19+
assert spec.name == "Example"
20+
assert spec.uuid == "123e4567-e89b-12d3-a456-426614174000"
21+
assert spec.dev is False
22+
assert spec.version is None
23+
assert spec.path is None
24+
assert spec.subdir is None
25+
assert spec.url is None
26+
assert spec.rev is None
27+
28+
# Test with all parameters
29+
spec = PkgSpec(
30+
name="Example",
31+
uuid="123e4567-e89b-12d3-a456-426614174000",
32+
dev=True,
33+
version="1.0.0",
34+
path="/path/to/pkg",
35+
subdir="subdir",
36+
url="https://example.com/pkg.git",
37+
rev="main",
38+
)
39+
assert spec.dev is True
40+
assert spec.version == "1.0.0"
41+
assert spec.path == "/path/to/pkg"
42+
assert spec.subdir == "subdir"
43+
assert spec.url == "https://example.com/pkg.git"
44+
assert spec.rev == "main"
45+
46+
# Test invalid name
47+
with pytest.raises(ValueError, match="name must be a non-empty string"):
48+
PkgSpec(name="", uuid="0000")
49+
with pytest.raises(ValueError, match="name must be a non-empty string"):
50+
PkgSpec(name=123, uuid="0000")
51+
52+
# Test invalid UUID
53+
with pytest.raises(ValueError, match="uuid must be a non-empty string"):
54+
PkgSpec(name="Example", uuid="")
55+
with pytest.raises(ValueError, match="uuid must be a non-empty string"):
56+
PkgSpec(name="Example", uuid=123)
57+
58+
# Test invalid dev flag
59+
with pytest.raises(TypeError, match="dev must be a boolean"):
60+
PkgSpec(name="Example", uuid="0000", dev="not-a-boolean")
61+
62+
# Test invalid version type
63+
with pytest.raises(TypeError, match="version must be a string, Version, or None"):
64+
PkgSpec(name="Example", uuid="0000", version=123)
65+
66+
# Test invalid path type
67+
with pytest.raises(TypeError, match="path must be a string or None"):
68+
PkgSpec(name="Example", uuid="0000", path=123)
69+
70+
# Test invalid subdir type
71+
with pytest.raises(TypeError, match="subdir must be a string or None"):
72+
PkgSpec(name="Example", uuid="0000", subdir=123)
73+
74+
# Test invalid url type
75+
with pytest.raises(TypeError, match="url must be a string or None"):
76+
PkgSpec(name="Example", uuid="0000", url=123)
77+
78+
# Test invalid rev type
79+
with pytest.raises(TypeError, match="rev must be a string or None"):
80+
PkgSpec(name="Example", uuid="0000", rev=123)

0 commit comments

Comments
 (0)