clan_cli: Remodeled ClanURI parser
All checks were successful
checks-impure / test (pull_request) Successful in 1m25s
checks / test (pull_request) Successful in 2m16s

This commit is contained in:
Luis Hebendanz 2023-12-05 18:16:51 +01:00
parent 22d5a61a51
commit cb984f6d43
2 changed files with 51 additions and 37 deletions

View File

@ -1,44 +1,50 @@
# Import the urllib.parse, enum and dataclasses modules
import urllib.parse
from enum import Enum, member
from dataclasses import dataclass
import dataclasses
import urllib.parse
from dataclasses import dataclass
from enum import Enum, member
from pathlib import Path
from typing import Dict
from .errors import ClanError
from typing import List
# Define an enum with different members that have different values
class ClanScheme(Enum):
# Use the dataclass decorator to add fields and methods to the members
@member
@dataclass
class HTTP():
url: str # The url field holds the HTTP URL
def __str__(self):
return f"HTTP({self.url})" # The __str__ method returns a custom string representation
@member
@dataclass
class HTTPS():
url: str # The url field holds the HTTPS URL
def __str__(self):
return f"HTTPS({self.url})" # The __str__ method returns a custom string representation
class HTTP:
url: str # The url field holds the HTTP URL
def __str__(self) -> str:
return f"HTTP({self.url})" # The __str__ method returns a custom string representation
@member
@dataclass
class FILE():
path: Path # The path field holds the local path
def __str__(self):
return f"FILE({self.path})" # The __str__ method returns a custom string representation
class HTTPS:
url: str # The url field holds the HTTPS URL
def __str__(self) -> str:
return f"HTTPS({self.url})" # The __str__ method returns a custom string representation
@member
@dataclass
class FILE:
path: Path # The path field holds the local path
def __str__(self) -> str:
return f"FILE({self.path})" # The __str__ method returns a custom string representation
# Parameters defined here will be DELETED from the nested uri
# so make sure there are no conflicts with other webservices
@dataclass
class ClanParameters():
class ClanParameters:
flake_attr: str | None
machine: str | None
# Define the ClanURI class
class ClanURI:
# Initialize the class with a clan:// URI
@ -56,7 +62,7 @@ class ClanURI:
# Parse the query string into a dictionary
self._query = urllib.parse.parse_qs(self._components.query)
params = {}
params: Dict[str, str | None] = {}
for field in dataclasses.fields(ClanParameters):
if field.name in self._query:
# Check if the field type is a list
@ -66,7 +72,9 @@ class ClanURI:
else:
values = self._query[field.name]
if len(values) > 1:
raise ClanError("Multiple values for parameter: {}".format(field.name))
raise ClanError(
"Multiple values for parameter: {}".format(field.name)
)
setattr(params, field.name, values[0])
# Remove the field from the query dictionary
@ -81,13 +89,12 @@ class ClanURI:
# Use the match statement to check the scheme and create a ClanScheme member with the value
match self._components.scheme:
case "http":
self.scheme = ClanScheme.HTTP.value(self._components.geturl())
self.scheme = ClanScheme.HTTP.value(self._components.geturl()) # type: ignore
case "https":
self.scheme = ClanScheme.HTTPS.value(self._components.geturl())
self.scheme = ClanScheme.HTTPS.value(self._components.geturl()) # type: ignore
case "file":
self.scheme = ClanScheme.FILE.value(Path(self._components.path))
self.scheme = ClanScheme.FILE.value(Path(self._components.path)) # type: ignore
case _:
raise ClanError("Unsupported scheme: {}".format(self._components.scheme))
raise ClanError(
"Unsupported scheme: {}".format(self._components.scheme)
)

View File

@ -1,18 +1,21 @@
from pathlib import Path
import pytest
from clan_cli.clan_uri import ClanURI, ClanScheme
from clan_cli.clan_uri import ClanScheme, ClanURI
from clan_cli.errors import ClanError
from pathlib import Path
def test_local_uri() -> None:
# Create a ClanURI object from a local URI
uri = ClanURI("clan://file:///home/user/Downloads")
match uri.scheme:
case ClanScheme.FILE.value(path):
assert path == Path("/home/user/Downloads") # type: ignore
assert path == Path("/home/user/Downloads") # type: ignore
case _:
assert False
def test_unsupported_schema() -> None:
with pytest.raises(ClanError, match="Unsupported scheme: ftp"):
# Create a ClanURI object from an unsupported URI
@ -25,10 +28,11 @@ def test_is_remote() -> None:
match uri.scheme:
case ClanScheme.HTTPS.value(url):
assert url == "https://example.com" # type: ignore
assert url == "https://example.com" # type: ignore
case _:
assert False
def remote_with_clanparams() -> None:
# Create a ClanURI object from a remote URI with parameters
uri = ClanURI("clan://https://example.com?flake_attr=defaultVM")
@ -37,19 +41,22 @@ def remote_with_clanparams() -> None:
match uri.scheme:
case ClanScheme.HTTPS.value(url):
assert url == "https://example.com" # type: ignore
assert url == "https://example.com" # type: ignore
case _:
assert False
def remote_with_all_params() -> None:
# Create a ClanURI object from a remote URI with parameters
uri = ClanURI("clan://https://example.com?flake_attr=defaultVM&machine=vm1&password=1234")
uri = ClanURI(
"clan://https://example.com?flake_attr=defaultVM&machine=vm1&password=1234"
)
assert uri.params.flake_attr == "defaultVM"
assert uri.params.machine == "vm1"
match uri.scheme:
case ClanScheme.HTTPS.value(url):
assert url == "https://example.com&password=1234" # type: ignore
assert url == "https://example.com&password=1234" # type: ignore
case _:
assert False
assert False