Skip to content

Commit 4875bd3

Browse files
committed
wip: dynamic dependencies
1 parent b519e67 commit 4875bd3

File tree

8 files changed

+28
-18
lines changed

8 files changed

+28
-18
lines changed

questionpy_common/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# QuestionPy is free software released under terms of the MIT license. See LICENSE.md.
33
# (c) Technische Universität Berlin, innoCampus <info@isis.tu-berlin.de>
44
from abc import ABC, abstractmethod
5+
from typing import NamedTuple
56

67
from pydantic_core import CoreSchema, core_schema
78

@@ -20,3 +21,13 @@ def __get_pydantic_core_schema__(cls, *_: object) -> CoreSchema:
2021

2122

2223
TranslatableString.register(str)
24+
25+
26+
class PackageNamespaceAndShortName(NamedTuple):
27+
"""Tuple of namespace and short name, identifying any version of a specific package."""
28+
29+
namespace: str
30+
short_name: str
31+
32+
def __str__(self) -> str:
33+
return f"@{self.namespace}/{self.short_name}"

questionpy_common/environment.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
from enum import Enum
88
from functools import total_ordering
99
from importlib.resources.abc import Traversable
10-
from typing import NamedTuple, Protocol
10+
from typing import Protocol
1111

1212
from pydantic import BaseModel, JsonValue
1313

14+
from questionpy_common import PackageNamespaceAndShortName
1415
from questionpy_common.api.package import QPyPackageInterface
1516
from questionpy_common.manifest import Bcp47LanguageTag, Manifest
1617

@@ -21,7 +22,6 @@
2122
"OnRequestCallback",
2223
"Package",
2324
"PackageInitFunction",
24-
"PackageNamespaceAndShortName",
2525
"PackageNotInitializedError",
2626
"PackageNotLoadedError",
2727
"PackagePermissions",
@@ -79,16 +79,6 @@ def __lt__(self, other: object) -> bool:
7979
return NotImplemented
8080

8181

82-
class PackageNamespaceAndShortName(NamedTuple):
83-
"""Tuple of namespace and short name, identifying any version of a specific package."""
84-
85-
namespace: str
86-
short_name: str
87-
88-
def __str__(self) -> str:
89-
return f"@{self.namespace}/{self.short_name}"
90-
91-
9282
class Package(Protocol):
9383
@property
9484
def manifest(self) -> Manifest: ...

questionpy_common/manifest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pydantic import AfterValidator, BaseModel, ByteSize, PositiveInt, StringConstraints, conset, field_validator
1111
from pydantic.fields import Field
1212

13+
from questionpy_common import PackageNamespaceAndShortName
1314
from questionpy_common.constants import NAME_MAX_LENGTH, RE_API, RE_SEMVER, RE_VALID_CHARS_NAME
1415
from questionpy_common.version_specifiers import QPyDependencyVersionSpecifier
1516

@@ -123,6 +124,10 @@ def ensure_contains_english_translation(
123124
def identifier(self) -> str:
124125
return f"@{self.namespace}/{self.short_name}"
125126

127+
@property
128+
def nssn(self) -> PackageNamespaceAndShortName:
129+
return PackageNamespaceAndShortName(self.namespace, self.short_name)
130+
126131

127132
class PackageFile(BaseModel):
128133
"""Represents a static file included in a built package."""
@@ -153,6 +158,9 @@ class AbstractDynamicQPyDependency(BaseModel, ABC):
153158
version: QPyDependencyVersionSpecifier | None = None
154159
include_prereleases: bool = False
155160

161+
def to_specifier_str(self) -> str:
162+
return f"@{self.namespace}/{self.short_name}{" " + str(self.version) if self.version else ""}"
163+
156164

157165
class DistDynamicQPyDependency(AbstractDynamicQPyDependency):
158166
locked: LockedDependencyInfo | None = None

questionpy_server/repository/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from questionpy_server.repository.models import RepoMeta, RepoPackage, RepoPackageIndex
1414
from questionpy_server.utils.logger import URLAdapter
1515

16-
_SCHEME_AND_AUTH_PATTERN = re.compile(r"^https?://(?:[^/]+@)?")
16+
_SCHEME_AND_AUTH_PATTERN = re.compile(r"^https?://(?:[^/@]+@)?")
1717
_FILENAME_SPECIAL_CHARACTERS_PATTERN = re.compile(r"[/\\?%*:|\"<>,;=\s]+")
1818

1919
def _url_to_safe_path_part(url: str) -> str:

questionpy_server/utils/manifest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ManifestError(QPyBaseError):
2525
pass
2626

2727

28-
def _read_manifest_sync(package_path: Path) -> ComparableManifest:
28+
def read_manifest_sync(package_path: Path) -> ComparableManifest:
2929
try:
3030
with ZipFile(package_path) as zip_file, zip_file.open(f"{DIST_DIR}/{MANIFEST_FILENAME}") as manifest_file:
3131
buffer = manifest_file.read(MAX_MANIFEST_SIZE + 1)
@@ -53,4 +53,4 @@ async def read_manifest(package_path: Path) -> ComparableManifest:
5353
Raises:
5454
ManifestError: if the manifest could not be read, is too large, or is invalid
5555
"""
56-
return await asyncio.to_thread(_read_manifest_sync, package_path)
56+
return await asyncio.to_thread(read_manifest_sync, package_path)

questionpy_server/worker/runtime/manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
Environment,
1717
OnRequestCallback,
1818
Package,
19-
PackageNamespaceAndShortName,
2019
PackagePermissions,
2120
PackageState,
2221
RequestInfo,
2322
set_qpy_environment,
2423
)
24+
from questionpy_common import PackageNamespaceAndShortName
2525
from questionpy_common.manifest import PackageType
2626
from questionpy_server.worker.runtime.connection import WorkerToServerConnection
2727
from questionpy_server.worker.runtime.messages import (

questionpy_server/worker/runtime/messages.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
from questionpy_common.api.qtype import InvalidQuestionStateError, OptionsFormValidationError
1515
from questionpy_common.api.question import QuestionModel
1616
from questionpy_common.elements import OptionsFormDefinition
17-
from questionpy_common.environment import PackageNamespaceAndShortName, PackagePermissions, RequestInfo
17+
from questionpy_common.environment import PackagePermissions, RequestInfo
18+
from questionpy_common import PackageNamespaceAndShortName
1819
from questionpy_common.error import QPyBaseError
1920
from questionpy_common.manifest import Manifest
2021
from questionpy_server.worker.runtime.package_location import PackageLocation

questionpy_server/worker/runtime/package.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
from questionpy_common.environment import (
1717
Environment,
1818
Package,
19-
PackageNamespaceAndShortName,
2019
PackageNotInitializedError,
2120
PackageNotLoadedError,
2221
PackageState,
2322
)
23+
from questionpy_common import PackageNamespaceAndShortName
2424
from questionpy_common.manifest import DistStaticQPyDependency, Manifest
2525
from questionpy_server.worker.runtime.package_location import (
2626
DirPackageLocation,

0 commit comments

Comments
 (0)