diff --git a/.gitignore b/.gitignore index 1d5e709..2c82418 100644 --- a/.gitignore +++ b/.gitignore @@ -73,5 +73,3 @@ venv/ # vscodium *vscode/ -# JetBrains -.idea/ \ No newline at end of file diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 685bcbd..97bc319 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -28,6 +28,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Unused normalize.css file - Identical links assigned in each translation file --> +## [0.3.1] - 2024-04-14 + +### Added +- Easier way to add templates. +- New templates : Data Science + +### Fixed +- Error on listing templates. + +### Changed +- Refactoring to introduce the TUI (interactive mode) + + ## [0.3.0] - 2023-08-05 ### Added @@ -71,6 +84,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved error reporting ### Fixed + - Fixed Issue [#8](https://github.com/HushmKun/Artec/issues/8) - Fixed error building structure if the source starts with a file. diff --git a/README.md b/README.md index 795cdac..743b68b 100644 --- a/README.md +++ b/README.md @@ -23,17 +23,21 @@ Create a JSON file to match the folder structure you desire $ vim structure.json # Paste the below into your file and modify as you desire -[ - {"folder": "{}"}, # Use '{}' to be replaced with project name. - {"file": "{}/__init__.py"}, - {"folder": "test"}, - {"file": "test/__init__.py"}, - {"file": "README.md"}, - {"file": "LICENSE"}, - {"file": "setup.py"}, - {"file": "setup.cfg"}, - {"file": "pyproject.toml"}, -] +{ + "folders": [ + "{}", + "test" + ], + "files": [ + "{}/__init__.py", + "test/__init__.py", + "README.md", + "LICENSE", + "setup.py", + "pyproject.toml" + ] +} + ``` How to execute ``` @@ -64,141 +68,14 @@ Examples: ``` ## Templates -
- Python - -Project Named Artec -``` -artec -├── artec -│ └── __main__.py -├── test -│ └── __init__.py -├── LICENSE -├── pyproject.toml -├── README.md -├── setup.cfg -└── setup.py - -2 directories, 7 files -``` -
- -
- Flask - -Project Named flaskr -``` -flaskr -. -├── flaskr -│ ├── auth.py -│ ├── blog -│ │ ├── create.html -│ │ ├── index.html -│ │ └── update.html -│ ├── blog.py -│ ├── db.py -│ ├── __init__.py -│ ├── schema.py -│ ├── static -│ │ └── style.css -│ └── templates -│ ├── auth -│ │ ├── login.html -│ │ └── register.html -│ └── base.html -├── LICENSE -├── pyproject.toml -├── README.md -├── setup.py -└── test - ├── conftest.py - ├── data.sql - ├── __init__.py - ├── test_auth.py - ├── test_blog.py - └── test_db.py - -7 directories, 22 files -``` -
-
- Node.Js - -Project Named Node -``` -Node -├── LICENSE -├── package.json -├── package-lock.json -├── README.md -└── src - ├── api - │ ├── controllers - │ │ └── user - │ │ ├── auth - │ │ │ ├── forgot-password.js - │ │ │ ├── login.js - │ │ │ ├── logout.js - │ │ │ ├── refresh-token.js - │ │ │ ├── register.js - │ │ │ ├── send-verification-code.js - │ │ │ └── verify-email.js - │ │ ├── delete-user.js - │ │ ├── edit - │ │ │ ├── change-password.js - │ │ │ └── edit-user.js - │ │ ├── get-user.js - │ │ └── index.js - │ ├── middlewares - │ │ ├── auth - │ │ │ ├── check-auth.js - │ │ │ └── check-authority.js - │ │ ├── image-upload.js - │ │ ├── index.js - │ │ ├── object-id-control.js - │ │ └── rate-limiter.js - │ ├── routes - │ │ ├── index.js - │ │ └── user.js - │ └── validators - │ ├── index.js - │ └── user.validator.js - ├── app.js - ├── config - │ └── index.js - ├── loaders - │ ├── express.js - │ ├── index.js - │ └── mongoose.js - ├── models - │ ├── index.js - │ ├── log.js - │ ├── token.js - │ └── user.js - └── utils - ├── helpers - │ ├── error-helper.js - │ ├── generate-random-code.js - │ ├── ip-helper.js - │ ├── jwt-token-helper.js - │ └── local-text-helper.js - ├── index.js - ├── lang - │ ├── en.json - │ ├── get-text.json - │ └── tr.json - ├── logger.js - └── send-code-to-email.js - -17 directories, 46 files -``` -
+- Python +- Flask +- Node.Js +- Data_Science ## Version - 0.3.0 + 0.3.1 ## Contributing Please refer to [Here](CONTRIBUTING.md) for contributing. diff --git a/artec/__main__.py b/artec/__main__.py index 23a2f7e..f36396c 100644 --- a/artec/__main__.py +++ b/artec/__main__.py @@ -1,9 +1,10 @@ from . import argparser as parser from . import boiler from . import logging, console_handler +from .temp import * __app_name__ = "Artec" -__version__ = "0.3.0" +__version__ = "0.3.1" __desc__ = "Creates a configurable python project \ template in a given directory." @@ -19,7 +20,6 @@ def main(): args = parser.main_args(__version__) console_handler.setLevel(ERROR_LOGING[args.verbose]) - builder = boiler.boiler_builder( args.source, args.target, args.template, args.git ) @@ -29,3 +29,4 @@ def main(): if __name__ == "__main__": main() + diff --git a/artec/argparser.py b/artec/argparser.py index b46bc19..52c5766 100644 --- a/artec/argparser.py +++ b/artec/argparser.py @@ -7,7 +7,7 @@ RawTextHelpFormatter, _VersionAction, ) -from .templates import templates +from .temp import * import sys @@ -15,10 +15,7 @@ class list_templates(_VersionAction): def __call__(self, parser: ArgumentParser, *args, **kwargs) -> None: formatter = parser._get_formatter() formatter.add_text( - "".join( - "Available templates\n\n", - "\n".join([f"> {key.title()}\t" for key in templates.keys()]), - ) + list_available_templates() ) parser._print_message(formatter.format_help(), sys.stdout) parser.exit() @@ -43,6 +40,7 @@ def __init__(self, appVersion): def setup(self): group = self.add_mutually_exclusive_group() + group.add_argument( "-s", "--source-file", @@ -60,13 +58,21 @@ def setup(self): required=False, ) + self.add_argument( "-o", "--output-directory", dest="target", help="Target output path where the structure will be created", type=str, - required=True, + ) + + self.add_argument( + "-i", + "--interactuve", + dest="interactive", + help="Runs artec in interactive mode.", + action="store_true", ) self.add_argument( @@ -107,7 +113,15 @@ def setup(self): def main_args(appVersion) -> Namespace: parser = Parser(appVersion) parser.setup() - return parser.parse_args() + args = parser.parse_args() + + if args.interactive: + print("Running Artec in interactive mode ....") + else: + if not args.target: + parser.error("The '-o' argument is required when not in interactive mode.") + + return args if __name__ == "__main__": diff --git a/artec/boiler.py b/artec/boiler.py index 78e61ad..74aeda8 100644 --- a/artec/boiler.py +++ b/artec/boiler.py @@ -6,10 +6,11 @@ import os from pathlib import Path from . import exceptions as ex -from . import templates as temps +from .temp import * from . import repo from . import logger + class boiler_builder: def __init__( self, @@ -29,13 +30,14 @@ def __init__( def _source_temp(self, template) -> list[dict[str, str]]: try: - if template in temps.templates: - structure = temps.templates[template].format(self.target) + if template in templates: + structure = format_project_structure(templates[template], self.target) + else: raise ex.InValidTemplate() except ex.InValidTemplate: - structure = temps.templates["python"].format(self.target) + structure = format_project_structure(templates["python"], self.target) return structure def _source(self, source) -> list[dict[str, str]]: @@ -44,33 +46,30 @@ def _source(self, source) -> list[dict[str, str]]: raise ex.NoSource() if os.path.isfile(source) and source.endswith(".json"): with open(source, "rt", encoding="utf-8") as file_data: - structure = temps.static_list(json.load(file_data)).format( + structure = format_project_structure(json.load(file_data), self.target ) else: raise ex.NotJsonFile() except Exception: - structure = temps.templates["python"].format(self.target) + structure = format_project_structure(templates["python"], self.target) return structure def build(self): print("> Creating folder structure: {}\n".format(self.target)) - for entry in self.structure: - for _type, name in entry.items(): - try: - joined = Path(os.path.join(self.target, name)) - if "folder" in _type: - self._make_folder(joined) - elif "file" in _type: - self._make_file(joined) - else: - raise ex.NotValidJson() - print("Created: %s" % joined) - except Exception: - pass + for folder in self.structure['folders']: + folder_path = os.path.join(self.target, folder) + self._make_folder(folder_path) + print("Created: {}".format(folder_path)) + + for file_path in self.structure['files']: + file_path = os.path.join(self.target, file_path) + self._make_file(file_path) + print("Created: {}".format(file_path)) + print() if self.git: @@ -83,7 +82,6 @@ def build(self): def _make_file(self, path): """Create an empty file in a given directory""" - path.parent.mkdir(parents=True, exist_ok=True) open(path, "a").close() def _make_folder(self, path): diff --git a/artec/temp/__init__.py b/artec/temp/__init__.py new file mode 100644 index 0000000..1cf3700 --- /dev/null +++ b/artec/temp/__init__.py @@ -0,0 +1,43 @@ +from os import listdir, path +from .. import exceptions as ex +from json import load + +DIR = path.dirname(path.abspath(__file__)) + + +def list_available_templates() -> str : + all_templates = "Available templates: \n\n" + all_templates += "\n".join( + [ + f"> {key.title()}\t" for key in templates.keys() + ] + ) + return all_templates + +def format_project_structure(template, project_name): + formatted_structure = {k: [] for k in template.keys()} + try: + for folder in template['folders']: + formatted_structure['folders'].append(folder.format(project_name)) + + for file_path in template['files']: + formatted_structure['files'].append(file_path.format(project_name)) + except Exception : + raise ex.NotValidJson() + + return formatted_structure + +def open_load(file_path): + with open(path.join(DIR, file_path), "rt") as file: + data = load(file) + + return data + + + +templates = { + filename.removesuffix(".json"): open_load(path.join(DIR, filename)) + for filename in listdir(DIR) + if filename.endswith(".json") +} + diff --git a/artec/temp/data_science.json b/artec/temp/data_science.json new file mode 100644 index 0000000..87c9349 --- /dev/null +++ b/artec/temp/data_science.json @@ -0,0 +1,38 @@ +{ + "folders": [ + "data", + "data/external", + "data/raw", + "data/processed", + "data/interim", + "docs", + "models", + "notebooks", + "refrences", + "reports", + "reports/figures", + "src", + "src/data", + "src/features", + "src/models", + "src/visualization" + ], + "files": [ + "docs/Makefile", + "docs/commands.rst", + "docs/conf.py", + "docs/getting-started.rst", + "docs/index.rst", + "docs/make.bat", + "src/__init__.py", + ".env", + ".gitignore", + "README.md", + "LICENSE", + "Makefile", + "requirements.txt", + "setup.py", + "tox.ini", + "test_environment.py" + ] +} \ No newline at end of file diff --git a/artec/temp/flask.json b/artec/temp/flask.json new file mode 100644 index 0000000..2177c66 --- /dev/null +++ b/artec/temp/flask.json @@ -0,0 +1,34 @@ +{ + "folders": [ + "{}", + "{}/templates", + "{}/templates/auth", + "{}/blog", + "{}/static", + "test" + ], + "files": [ + "{}/__init__.py", + "{}/db.py", + "{}/schema.py", + "{}/auth.py", + "{}/blog.py", + "{}/templates/base.html", + "{}/templates/auth/login.html", + "{}/templates/auth/register.html", + "{}/blog/create.html", + "{}/blog/index.html", + "{}/blog/update.html", + "{}/static/style.css", + "test/__init__.py", + "test/conftest.py", + "test/data.sql", + "test/test_db.py", + "test/test_auth.py", + "test/test_blog.py", + "README.md", + "LICENSE", + "setup.py", + "pyproject.toml" + ] +} diff --git a/artec/temp/nodejs.json b/artec/temp/nodejs.json new file mode 100644 index 0000000..af21726 --- /dev/null +++ b/artec/temp/nodejs.json @@ -0,0 +1,69 @@ +{ + "folders": [ + "src", + "src/api", + "src/api/controllers", + "src/api/controllers/user", + "src/api/controllers/user/auth", + "src/api/controllers/user/edit", + "src/api/middlewares", + "src/api/middlewares/auth", + "src/api/routes", + "src/api/validators", + "src/config", + "src/loaders", + "src/models", + "src/utils", + "src/utils/helpers", + "src/utils/lang" + ], + "files": [ + "src/api/controllers/user/auth/forgot-password.js", + "src/api/controllers/user/auth/login.js", + "src/api/controllers/user/auth/logout.js", + "src/api/controllers/user/auth/refresh-token.js", + "src/api/controllers/user/auth/register.js", + "src/api/controllers/user/auth/send-verification-code.js", + "src/api/controllers/user/auth/verify-email.js", + "src/api/controllers/user/edit/change-password.js", + "src/api/controllers/user/edit/edit-user.js", + "src/api/controllers/user/delete-user.js", + "src/api/controllers/user/get-user.js", + "src/api/controllers/user/index.js", + "src/api/middlewares/auth/check-auth.js", + "src/api/middlewares/auth/check-authority.js", + "src/api/middlewares/image-upload.js", + "src/api/middlewares/index.js", + "src/api/middlewares/object-id-control.js", + "src/api/middlewares/rate-limiter.js", + "src/api/routes/index.js", + "src/api/routes/user.js", + "src/api/validators/index.js", + "src/api/validators/user.validator.js", + "src/config/index.js", + "src/loaders/index.js", + "src/loaders/express.js", + "src/loaders/mongoose.js", + "src/models/index.js", + "src/models/log.js", + "src/models/token.js", + "src/models/user.js", + "src/utils/helpers/error-helper.js", + "src/utils/helpers/generate-random-code.js", + "src/utils/helpers/ip-helper.js", + "src/utils/helpers/jwt-token-helper.js", + "src/utils/helpers/local-text-helper.js", + "src/utils/lang/en.json", + "src/utils/lang/get-text.json", + "src/utils/lang/tr.json", + "src/utils/index.js", + "src/utils/logger.js", + "src/utils/send-code-to-email.js", + "src/app.js", + ".env.sample", + "README.md", + "LICENSE", + "package.json", + "package-lock.json" + ] +} diff --git a/artec/temp/python.json b/artec/temp/python.json new file mode 100644 index 0000000..a36d2bc --- /dev/null +++ b/artec/temp/python.json @@ -0,0 +1,14 @@ +{ + "folders": [ + "{}", + "test" + ], + "files": [ + "{}/__init__.py", + "test/__init__.py", + "README.md", + "LICENSE", + "setup.py", + "pyproject.toml" + ] +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index d7062da..ca1914d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ exclude = ["img*"] [project] name = "Artec" -version = "0.3.0" +version = "0.3.1" authors = [ { name="HushmKun", email="HushmKun@outlook.com" }, { name="Link-", email="bsm.dgdy@gmail.com" }, diff --git a/test/resources/structure.json b/test/resources/structure.json index 7569ac8..785dc1d 100644 --- a/test/resources/structure.json +++ b/test/resources/structure.json @@ -1,11 +1,14 @@ -[ - {"folder": "{}"}, - {"file": "{}/__init__.py"}, - {"folder": "test"}, - {"file": "test/__init__.py"}, - {"file": "README.md"}, - {"file": "LICENSE"}, - {"file": "setup.py"}, - {"file": "setup.cfg"}, - {"file": "pyproject.toml"} -] \ No newline at end of file +{ + "folders": [ + "{}", + "test" + ], + "files": [ + "{}/__init__.py", + "test/__init__.py", + "README.md", + "LICENSE", + "setup.py", + "pyproject.toml" + ] +} diff --git a/test/test_boiler.py b/test/test_boiler.py index 8e9cfd6..9185872 100644 --- a/test/test_boiler.py +++ b/test/test_boiler.py @@ -3,7 +3,8 @@ import git from pathlib import Path from artec.boiler import boiler_builder -from artec.templates import static_list, templates + +from artec.temp import * VAILD_JSON = Path("./test/resources/structure.json") INVAILD_JSON = Path("./test/resources/structure.txt") @@ -15,19 +16,19 @@ def test_init(self): source="structure.json", target="target" ) self.assertEqual(builder.target, "target") - self.assertIsInstance(builder.structure, list) + self.assertIsInstance(builder.structure, dict) def test_source_temp(self): builder = boiler_builder( template="python", target="target" ) self.assertEqual( - builder.structure, templates["python"].format("target") + builder.structure, format_project_structure(templates["python"], "target") ) def test_source(self): with open(VAILD_JSON, "rt", encoding="utf-8") as file_data: - structure = static_list(json.load(file_data)).format("target") + structure = format_project_structure(json.load(file_data),"target") builder = boiler_builder( source=VAILD_JSON, target="target" ) @@ -56,19 +57,19 @@ def test_exception_handling(self): source=INVAILD_JSON, target="target" ) self.assertEqual( - builder.structure, templates["python"].format("target") + builder.structure, format_project_structure(templates["python"],"target") ) builder = boiler_builder( template="invalid", target="target" ) self.assertEqual( - builder.structure, templates["python"].format("target") + builder.structure, format_project_structure(templates["python"],"target") ) builder = boiler_builder(target="target") self.assertEqual( - builder.structure, templates["python"].format("target") + builder.structure, format_project_structure(templates["python"],"target") )