diff --git a/README.md b/README.md index 1dfa35a..8ca62b8 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ pip install pyttman pyttman new app my_first_app # Create an Ability module with files from a template -pyttman new ability +pyttman new ability ability_name my_first_app # Run it in dev mode pyttman dev my_first_app diff --git a/devtools/build.py b/devtools/build.py index c383cb3..a1b3f7f 100644 --- a/devtools/build.py +++ b/devtools/build.py @@ -6,11 +6,13 @@ # Set the current working dir to parent directory sys.path.append(Path.cwd().parent.as_posix()) -os.chdir("..") -CATALOGS = ("build", "dist") +CATALOGS = ("build", "dist") BUILD_CMD = "python -m setup sdist bdist_wheel".split() + if __name__ == "__main__": - [shutil.rmtree(i) for i in CATALOGS] + subprocess.Popen(BUILD_CMD) + [shutil.rmtree(i) for i in CATALOGS if Path(i).exists()] subprocess.run(BUILD_CMD) + diff --git a/devtools/create_environment.py b/devtools/create_environment.py index 30c500e..0c8473e 100644 --- a/devtools/create_environment.py +++ b/devtools/create_environment.py @@ -7,7 +7,11 @@ from time import sleep sys.path.append(Path.cwd().parent.as_posix()) -os.chdir("..") + +if not Path("setup.py").exists(): + print("You're not in the right directory. Run this script from the " + r"project's root directory, e.g. 'C:\users\your_user\projects\pyttman'.") + exit(-1) LAB_ENV_PATH = Path.cwd() / Path("dev_env") BUILD_OUTPUT_PATH = Path.cwd() / "dist" @@ -17,10 +21,7 @@ shutil.rmtree((LAB_ENV_PATH / "venv").as_posix()) if not Path("dist").exists(): - print("\nCannot create local testing environment as there is no " - "build generated for the current local version of Pyttman.", - "Run 'build.py' to create one.") - exit(-1) + subprocess.check_call("python devtools/build.py".split()) LAB_ENV_PATH.mkdir(exist_ok=True) os.chdir(LAB_ENV_PATH.as_posix()) @@ -39,5 +40,16 @@ subprocess.run(f"{venv_python} -m pip install multidict".split()) subprocess.run(f"{venv_python} -m pip install {package_file}".split()) - print("\nFinished! You can now create an app and start testing in " - f"{LAB_ENV_PATH.as_posix()}.") + clear_sc = "clear" if os.name == "posix" else "cls" + os.system(clear_sc) + + os.system("cls") + print("\nFinished! Here's how to get started:", + f"1. Activate the virtual environment:\n\tcd dev_env\n\tvenv/scripts/activate", + f"2. Run the command 'pyttman' to see available commands to the Pyttman CLI", + "3. If it's the first time you're running Pyttman, run 'pyttman new app {app_name}' to create a new project." + "4. Run 'pyttman dev {app_name}' to start the development server.", + "5. If you've made changes to the Pyttman framework which you want to test in your testing project, " + "run this script again. Your app will be left untouched, but the Pyttman version is upgraded to " + "your current HEAD in the Pyttman repo.", + sep="\n") diff --git a/pyttman/core/internals.py b/pyttman/core/internals.py index 9a4ac97..bc8f39e 100644 --- a/pyttman/core/internals.py +++ b/pyttman/core/internals.py @@ -5,6 +5,9 @@ from dataclasses import dataclass, field from datetime import datetime from typing import Any +import json +from collections import UserDict + import pyttman from pyttman.core.containers import MessageMixin, Reply @@ -32,7 +35,6 @@ def depr_graceful(message: str, version: str): out = f"{message} - This was deprecated in version {version}." warnings.warn(out, DeprecationWarning) - class Settings: """ Dataclass holding settings configured in the settings.py @@ -48,7 +50,10 @@ class Settings: aren't valid settings. """ - def __init__(self, **kwargs): + def __init__(self, dictionary=None, **kwargs): + if dictionary is None: + dictionary = {} + self.__dict__.update(dictionary) self.APPEND_LOG_FILES: bool = True self.MIDDLEWARE: dict | None = None self.ABILITIES: list | None = None @@ -59,15 +64,30 @@ def __init__(self, **kwargs): self.APP_NAME: str | None = None self.LOG_FORMAT: str | None = None self.LOG_TO_STDOUT: bool = False + self.STATIC_FILES_DIR: Path | None = None + self.TIME_ZONE: pytz.timezone = None - [setattr(self, k, v) for k, v in kwargs.items() + [self._set_attr(k, v) for k, v in kwargs.items() if not inspect.ismodule(v) and not inspect.isfunction(v)] + def __getitem__(self, item): + return self.__dict__[item] + + def _set_attr(self, k, v): + tmp = v + if isinstance(v, dict): + tmp = Settings._dict_to_object(v) + + setattr(self, k, tmp) + def __repr__(self): _attrs = {name: value for name, value in self.__dict__.items()} return f"Settings({_attrs})" + @staticmethod + def _dict_to_object(dictionary): + return json.loads(json.dumps(dictionary), object_hook=Settings) def _generate_name(name): """ diff --git a/requirements.txt b/requirements.txt index 41e646c..733924c 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/tests/core/test_settings.py b/tests/core/test_settings.py new file mode 100644 index 0000000..a225584 --- /dev/null +++ b/tests/core/test_settings.py @@ -0,0 +1,32 @@ +from tests.module_helper import PyttmanInternalBaseTestCase +from pyttman.core.internals import Settings + +from importlib import import_module +import pytest + +@pytest.fixture +def mockSettings(): + + mock_settings = { + "d":{ + "k1":"v1", + "k2":{ + "a":"a", + "b":"b" + } + }, + "foo":"bar" + } + + return Settings(**mock_settings) + +def test_read_settings_with_dictionary(mockSettings): + assert mockSettings.d.k2.a == "a" + assert mockSettings.d["k2"].a == "a" + assert mockSettings.d["k2"]["a"] == "a" + + assert mockSettings.d.k1 == "v1" + assert mockSettings.d["k1"] == "v1" + + assert mockSettings.foo == "bar" +