diff --git a/.gitignore b/.gitignore index 878e97f6fca1edcfbbb56b5ec1808e4caa724037..997ec81335d8b059cd3a1265e62520d79a98692f 100644 --- a/.gitignore +++ b/.gitignore @@ -37,7 +37,7 @@ MANIFEST pip-log.txt pip-delete-this-directory.txt -# Unit test / coverage reports +# Unit tests / coverage reports htmlcov/ .tox/ .nox/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..daa84cdf68811adf5d6af1132a452cc83d7c6433 --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +# Makefile for Code Generator +# +# GitHb: https://github.com/wj-Mcat/code-generator +# +# Author: Jingjing WU (吴京京) + +SOURCE_GLOB=$(wildcard bin/*.py src/**/*.py tests/**/*.py examples/*.py) + +IGNORE_PEP=E203,E221,E241,E272,E501,F811 + +# help scripts to find the right place of wechaty module +export PYTHONPATH=src/ + +.PHONY: all +all : clean lint + +.PHONY: clean +clean: + rm -fr dist/* ./build/ ./dist/ + +.PHONY: lint +lint: pylint pycodestyle flake8 mypy + + +# disable: TODO list temporay +.PHONY: pylint +pylint: + pylint \ + --load-plugins pylint_quotes \ + --disable=W0511,R0801,cyclic-import \ + $(SOURCE_GLOB) + +.PHONY: pycodestyle +pycodestyle: + pycodestyle \ + --statistics \ + --count \ + --ignore="${IGNORE_PEP}" \ + $(SOURCE_GLOB) + +.PHONY: flake8 +flake8: + flake8 \ + --ignore="${IGNORE_PEP}" \ + $(SOURCE_GLOB) + +.PHONY: mypy +mypy: + MYPYPATH=stubs/ mypy \ + $(SOURCE_GLOB) + +.PHONY: install +install: + pip install -r requirements.txt + pip install -r requirements-dev.txt + +.PHONY: pytest +pytest: + pytest src/ tests/ + +.PHONY: test-unit +test-unit: pytest + +.PHONY: test +test: lint pytest + +code: + code . + +.PHONY: dist +dist: + python setup.py sdist bdist_wheel + +.PHONY: publish +publish: + PATH=~/.local/bin:${PATH} twine upload dist/* + +.PHONY: version +version: + @newVersion=$$(awk -F. '{print $$1"."$$2"."$$3+1}' < VERSION) \ + && echo $${newVersion} > VERSION \ + && echo VERSION = \'$${newVersion}\' > src/version.py \ + && git add VERSION src/version.py \ + && git commit -m "$${newVersion}" > /dev/null \ + && git tag "v$${newVersion}" \ + && echo "Bumped version to $${newVersion}" diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..821f3a4f70a98278a35287749766ee7ef2d542c0 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# code-generator + +![](https://img.shields.io/badge/pypi-0.0.2-brightgreen) +![](https://img.shields.io/badge/build-passing-brightgreen) +![](https://img.shields.io/badge/python-3.7+-brightgreen) + + +![](./docs/logo.png) + +## features + +- can generate all-language code, eg: `python`, `vue`, `java`, `scala`, `go` and more +- generate code with powerful template **** +- template can contains control command, eg: `if`, `for`, `set variable` +- can **easily** run on other template repo. + +## quick start + +1 . install command +```shell script +pip install code-generator +``` + +2 . prepare `templates`, `plugins`, `config` + +you should set the prepared + +3 . generate codes + + +## changelog + +- version 0.0.2 + - complete the basic interface: `templates`, `plugins`, `config` + - can run well for template code generator + +- version 0.0.1 + - deploy the pypi package + - complete a simple code-generator + +## Author + +![[wj-Mcat](https://www.github.com/wj-Mcat)](https://avatars3.githubusercontent.com/u/10242208?s=260) + +[wj-Mcat](https://www.github.com/wj-Mcat) diff --git a/VERSION b/VERSION index 8a9ecc2ea99d607e92feae1656ddbf6fdd82a2c1..7bcd0e3612da7c517106f9b581a8beb53d4b0a97 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.1 \ No newline at end of file +0.0.2 \ No newline at end of file diff --git a/docs/logo.png b/docs/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f31b52202dc50838e862fc9bab7a8785912fe9b4 Binary files /dev/null and b/docs/logo.png differ diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000000000000000000000000000000000000..22ed6e88c6ae6b234a2615c7844a19de5bd8ade2 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,11 @@ +flake8 +mypy +mypy_extensions +pycodestyle +pylint +pylint-quotes +pytest +pytype==2020.2.20 +semver +requests +twine diff --git a/setup.py b/setup.py index 28b5f5a543a23d9202954c2277d2d8a86209a17f..5ddb6c1d5d37cf5a1fb44ca5a03232948030148a 100644 --- a/setup.py +++ b/setup.py @@ -26,18 +26,20 @@ with open("./VERSION", 'r+') as f: with open('./requirements.txt', 'r+') as f: requirements = f.readlines() +with open('./README.md', 'r+') as f: + long_description = f.read() + setup( name='code-generator', version=VERSION, - description="a simple code generator for ", - long_description='a templated code generator for all language, especially ' - 'for boring code', + description="a simple code generator for all-language", + long_description=long_description, keywords='code-gen,code-generator,python,code-snippet', author='wj-Mcat', author_email='1435130236@qq.com', license='Apache 2', packages=find_packages('src'), - package_dir = { + package_dir={ "": "src" }, include_package_data=True, diff --git a/src/code_generator/config.py b/src/code_generator/config.py index edabc7ead6b4ac4a573f7365319edb91f007a3f6..0872922b1cec12e253d6587c1b25cb8dc12dfeaa 100644 --- a/src/code_generator/config.py +++ b/src/code_generator/config.py @@ -21,16 +21,16 @@ from __future__ import annotations import logging -from jinja2 import Template - def get_logger(): """get the logger""" log_formatter = logging.Formatter( - fmt='%(asctime)s - %(name)s - %(levelname)s - %(filename)s - %(funcName)s - %(message)s') + fmt='%(asctime)s - %(name)s - %(levelname)s - %(filename)s - ' + '%(funcName)s - %(message)s') + + logger = logging.getLogger('CodeGenerator') - logger = logging.getLogger("CodeGenerator") - logger.handlers = [] + logger.handlers.clear() logger.setLevel(logging.DEBUG) logger.propagate = False diff --git a/src/code_generator/loader.py b/src/code_generator/loader.py index cbef6074b38a0f92f48f8d6a084697a6097d1cfd..1e08426708dd920e4282aafced34c9129592a99c 100644 --- a/src/code_generator/loader.py +++ b/src/code_generator/loader.py @@ -27,10 +27,11 @@ from jinja2.runtime import Macro from .config import get_logger - +# pylint: disable=invalid-name log = get_logger() +# pylint: disable=too-few-public-methods class Loader(metaclass=ABCMeta): """load the plugins from local or default path""" def __init__(self, file_or_dir: str): @@ -77,6 +78,7 @@ class Loader(metaclass=ABCMeta): self.files[file_name] = code +# pylint: disable=too-few-public-methods class TemplateLoader(Loader): """template loader""" def __init__(self, file_or_dir: str = 'templates'): @@ -89,7 +91,7 @@ class TemplateLoader(Loader): templates: Dict[str, Template] = {} for key, template in self.files.items(): if plugins is not None: - template = "{plugin}\n{template}".format( + template = '{plugin}\n{template}'.format( plugin=plugins, template=template ) log.info(template) @@ -103,24 +105,30 @@ class PluginLoader(Loader): super(PluginLoader, self).__init__(file_or_dir) def _load_plugins(self) -> Dict[str, str]: + """load plugins to dict""" self._load_files() return self.files def load_to_file(self) -> str: + """load plugins content to a single file content, so we can compile it + and add it to all template""" files = self._load_plugins() return '\n'.join(files.values()) def load_plugin_descriptions(self) -> Dict[str, str]: + """we can set plugin with different description, so that we can use it + to select different plugins to different field""" descriptions: Dict[str, str] = {} plugins = self._load_plugins() - for name, plugin in plugins.items(): + for _, plugin in plugins.items(): module = Template(plugin).module attrs = dir(module) macros = [(attr, getattr(module, attr)) for attr in attrs if isinstance(getattr(module, attr), Macro)] # first we only load the name of plugin - for macro_name, macro in macros: + # TODO -> we can refactor it later + for macro_name, _ in macros: if macro_name not in descriptions: descriptions[macro_name] = macro_name diff --git a/src/code_generator/main.py b/src/code_generator/main.py index 8113d73a7fcd4f7609acfbb06ddc514b253b7757..d029fe1c503ee3e403e1296e7cac2b777accc30e 100644 --- a/src/code_generator/main.py +++ b/src/code_generator/main.py @@ -23,21 +23,21 @@ import json from argparse import ArgumentParser import os -from jinja2 import Template - from .config import get_logger from .loader import TemplateLoader, PluginLoader - +# pylint: disable=invalid-name log = get_logger() -args = {} +# pylint: disable=invalid-name +args: dict = {} def run_server(): - pass + """we can run a simple http server to display the code-generator""" def _save_to_file(template_dir: str, file_name: str, content: str): + """save template result to the file""" if not os.path.exists(template_dir): os.mkdir(template_dir) path = os.path.join(template_dir, file_name) @@ -56,6 +56,7 @@ def _read_to_json(file: str) -> dict: def render_by_config(): + """render the template with config file mode""" config = _read_to_json(args['config']) plugins = PluginLoader(args['plugins']).load_to_file() log.info(plugins) @@ -67,6 +68,7 @@ def render_by_config(): def main(): + """main entry of the code-generator""" parser = ArgumentParser() subparsers = parser.add_subparsers(help='sub command') serve_parser = subparsers.add_parser(name='serve') diff --git a/tests/test_render.py b/tests/test_render.py new file mode 100644 index 0000000000000000000000000000000000000000..64dfeb52837722b883d15bb4dbe5329e0e6fae84 --- /dev/null +++ b/tests/test_render.py @@ -0,0 +1,6 @@ +"""tests code""" +import pytest + + +def test_loader(): + """tests template loader"""