Skip to content

Commit

Permalink
Use application context manager
Browse files Browse the repository at this point in the history
  • Loading branch information
jeckel committed Nov 4, 2024
1 parent 02cf65d commit ee73fc8
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 50 deletions.
5 changes: 2 additions & 3 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import typer
from dependency_injector import providers

from service_locator import ServiceContainer
from models import Project
Expand All @@ -10,9 +9,9 @@

@app.command()
def tui(project_path: str) -> None:
project = Project.from_json(json_path=project_path)
ServiceContainer()
tui_app = MainApp(project)
ServiceContainer.context().project = Project.from_json(json_path=project_path)
tui_app = MainApp()
tui_app.run()


Expand Down
18 changes: 18 additions & 0 deletions src/models/app_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from typing import Optional

from pydantic import BaseModel

from models import Project


class AppContext(BaseModel):
project: Optional[Project] = None

# Composer related context
composer_updatable_packages: Optional[dict[str, str]] = None

@property
def current_project(self) -> Project:
if self.project is None:
raise RuntimeError("No project set in AppContext")
return self.project
13 changes: 7 additions & 6 deletions src/presentation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from textual.widgets import Footer, Header, TabbedContent, TabPane

from models import Project
from service_locator import ServiceContainer
from .component.message import TerminalCommandRequested

from .composer import ComposerContainer, ComposerCommandRequested
from .composer import ComposerCommandRequested
from .docker import DockerContainer
from .summary import ProjectSummaryContainer
from .component import Sidebar, TerminalModal, NonShellCommand
Expand All @@ -27,13 +28,13 @@ class MainApp(App[None]):
CSS_PATH = "../tcss/layout.tcss"
_project: Project

def __init__(self, project: Project):
self._project = project
def __init__(self):
self._project = ServiceContainer.context().current_project
super().__init__()
self.title = f"DX Companion - {project.name}"
self.title = f"DX Companion - {self._project.name}"

def compose(self) -> ComposeResult:
yield Sidebar(project=self._project, classes="-hidden")
yield Sidebar(classes="-hidden")
yield Header()
with TabbedContent(initial="summary-pan"):
with TabPane(title="Summary", id="summary-pan"):
Expand All @@ -49,7 +50,7 @@ def action_toggle_sidebar(self) -> None:
def action_composer_script(self, event: ComposerCommandRequested) -> None:
def refresh_composer(result: bool | None):
if event.refresh_composer_on_success and result:
self.query_one(ComposerContainer).action_refresh()
ServiceContainer.composer_client().reset_updatable_packages()

self.query_one(Sidebar).add_class("-hidden")
self.app.push_screen(
Expand Down
18 changes: 7 additions & 11 deletions src/presentation/component/sidebar.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
from textual.app import ComposeResult
from textual.containers import Container
from textual.widgets import OptionList
from textual.widgets.option_list import Option, Separator


from models import Project
from presentation.component.action_option_list import ActionOptionList
from presentation.composer.composer_script_option_list import ComposerScriptOptionList
from service_locator import ServiceContainer
Expand All @@ -25,20 +21,20 @@ class Sidebar(Container):
}
"""

def __init__(self, project: Project, **kwargs):
self.project = project
def __init__(self, **kwargs):
self._project = ServiceContainer.context().current_project
super().__init__(**kwargs)
self.add_class("-hidden")

def compose(self) -> ComposeResult:

if len(ServiceContainer.composer_client().scripts(self.project)) > 0:
yield ComposerScriptOptionList(self.project)
if self.project.actions is None:
if len(ServiceContainer.composer_client().scripts(self._project)) > 0:
yield ComposerScriptOptionList(self._project)
if self._project.actions is None:
return
for action_group, actions in self.project.actions.items():
for action_group, actions in self._project.actions.items():
if len(actions) > 0:
yield ActionOptionList(
project=self.project, actions=actions, group_name=action_group
project=self._project, actions=actions, group_name=action_group
)
# yield ActionOptionList(project=self.project)
17 changes: 7 additions & 10 deletions src/presentation/composer/composer_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from textual.widgets import Button
from textual.worker import Worker, WorkerState

from models import Project
from models.composer import Composer
from service_locator import ServiceContainer

Expand All @@ -29,9 +28,9 @@ class ComposerContainer(Container):
}
"""

def __init__(self, project: Project, **kwargs):
self.project = project
self.composer = Composer.from_json(project.path)
def __init__(self, **kwargs):
self._project = ServiceContainer.context().current_project
self.composer = Composer.from_json(self._project.path)
super().__init__(**kwargs)

def compose(self) -> ComposeResult:
Expand All @@ -55,25 +54,23 @@ def compose(self) -> ComposeResult:

def action_refresh(self) -> None:
self.loading = True
self._load_composer(no_cache=True)
self._load_composer()

async def on_mount(self):
self.loading = True
self._load_composer()

@work(exclusive=True, thread=True)
async def _load_composer(self, no_cache: bool = False) -> dict[str, str]:
return ServiceContainer.composer_client().updatable_packages(
self.project, no_cache
)
async def _load_composer(self) -> dict[str, str]:
return ServiceContainer.composer_client().updatable_packages()

@on(Worker.StateChanged)
async def refresh_listview(self, event: Worker.StateChanged) -> None:
"""Called when the worker state changes."""
if event.state != WorkerState.SUCCESS:
return
packages_updatable = event.worker.result
composer = ServiceContainer.composer_client().composer_json(self.project)
composer = ServiceContainer.composer_client().composer_json(self._project)
package_table: ComposerPackagesTable = self.query_one(
"#composer-packages-table"
)
Expand Down
14 changes: 9 additions & 5 deletions src/presentation/composer/composer_screen.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from textual import on
from textual.app import ComposeResult
from textual.events import ScreenResume
from textual.screen import Screen
from textual.widgets import Header, Footer

from models import Project
from .composer_container import ComposerContainer
from presentation.component.sidebar import Sidebar

Expand All @@ -12,15 +13,18 @@ class ComposerScreen(Screen):
("escape", "return", "Return to project"),
}

def __init__(self, project: Project, **kwargs):
self._project = project
def __init__(self, **kwargs):
super().__init__(**kwargs)

def compose(self) -> ComposeResult:
yield Sidebar(project=self._project, classes="-hidden")
yield Sidebar(classes="-hidden")
yield Header()
yield ComposerContainer(self._project)
yield ComposerContainer()
yield Footer()

def action_return(self):
self.dismiss()

@on(ScreenResume)
def screen_resume(self):
self.query_one(ComposerContainer).action_refresh()
6 changes: 2 additions & 4 deletions src/presentation/summary/composer_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ def get_composer_panel(self) -> Table:

@work(exclusive=True, thread=True)
async def _load_composer(self, no_cache: bool = False) -> dict[str, str]:
return ServiceContainer.composer_client().updatable_packages(
self._project, no_cache
)
return ServiceContainer.composer_client().updatable_packages()

@on(Worker.StateChanged)
async def refresh_listview(self, event: Worker.StateChanged) -> None:
Expand All @@ -112,4 +110,4 @@ async def refresh_listview(self, event: Worker.StateChanged) -> None:

@on(Button.Pressed, "#toggle_composer_tab")
def on_composer_manage(self):
self.app.push_screen(ComposerScreen(self._project))
self.app.push_screen(ComposerScreen())
5 changes: 3 additions & 2 deletions src/service_locator.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from dependency_injector import containers, providers

from models import Project
from models.app_context import AppContext
from services import DockerClient, ComposerClient


class ServiceContainer(containers.DeclarativeContainer):
config = providers.Configuration()
docker_client = providers.Singleton(DockerClient)
composer_client = providers.Singleton(ComposerClient)
context = providers.Singleton(AppContext)
composer_client = providers.Singleton(ComposerClient, context=context)
# project = providers.Factory(Project)

# api_client = providers.Singleton(
Expand Down
23 changes: 14 additions & 9 deletions src/services/composer_client.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
from __future__ import annotations
import subprocess
from uuid import UUID

from models import Project
from models.app_context import AppContext
from models.composer import Composer
from .base_service import BaseService


class ComposerClient(BaseService):
_updatable_packages: dict[UUID, dict[str, str]] = {}
def __init__(self, context: AppContext):
self._context = context

def updatable_packages(
self, project: Project, no_cache: bool = False
) -> dict[str, str]:
if project.id_ in self._updatable_packages is not None and not no_cache:
return self._updatable_packages[project.id_]
def updatable_packages(self) -> dict[str, str]:
project = self._context.current_project

if self._context.composer_updatable_packages is not None:
return self._context.composer_updatable_packages

with subprocess.Popen(
["composer", "update", "--dry-run", "--no-ansi"],
Expand All @@ -34,8 +36,11 @@ def updatable_packages(
version_info = parts[1].strip().rstrip(")")
target_version = version_info.split("=>")[-1].strip()
packages[package_name] = target_version
self._updatable_packages[project.id_] = packages
return self._updatable_packages[project.id_]
self._context.composer_updatable_packages = packages
return self._context.composer_updatable_packages

def reset_updatable_packages(self) -> None:
self._context.composer_updatable_packages = None

@staticmethod
def composer_json(project: Project) -> None | Composer:
Expand Down

0 comments on commit ee73fc8

Please sign in to comment.