Skip to content

Commit 3ee1ef2

Browse files
committed
Add python project
1 parent 6e04f10 commit 3ee1ef2

File tree

10 files changed

+1880
-0
lines changed

10 files changed

+1880
-0
lines changed

.type_stubs/.gitkeep

Whitespace-only changes.

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Python Poetry Template
2+
3+
This template is designed to make it easy to set up a Python project that is well-structured, organized, and easy to maintain. It comes pre-configured with several tools that will help you develop your project more efficiently, including:
4+
5+
- Visual Studio Code integration: with the `RunOnSave`, `even-better-toml` and `ruff` extensions installed, you can format, lint, and type-check your code automatically every time you save a file.
6+
- Type checking: this template is configured to use `mypy` and `pyright` to automatically infer types when possible, without imposing strict typing requirements on your code.
7+
- Linting: `ruff`, an extremely fast Python linter, written in Rust is configured well to help you catch and fix code style issues.
8+
- Formatting: `yapf`, `ruff`, and `unify` are configured to help you keep your code clean and well-organized.
9+
- Testing: `pytest` is configured to make it easy to run tests, and `pytest-cov` is configured to help you measure code coverage.
10+
- Dependency management: `poetry` is configured to help you manage your project's dependencies.
11+
- Toolkits: `invoke` is configured to provide a range of useful tasks, such as running your code, running tests, formatting your code, and checking your code style and types. These tasks are fully configurable in the [tasks.py](tasks.py) file.
12+
13+
## Installation
14+
15+
To install this template, simply follow these steps:
16+
17+
```sh
18+
git clone [email protected]:code-yeongyu/Python-Poetry-Template.git
19+
cd Python-Poetry-Template
20+
poetry install
21+
code --install-extension emeraldwalk.RunOnSave
22+
code --install-extension tamasfe.even-better-toml
23+
code --install-extension charliermarsh.ruff
24+
```
25+
26+
## Usage
27+
28+
To use this template, you can follow these steps:
29+
30+
### Open Shell
31+
32+
To open a shell in the project directory, use the following command:
33+
34+
```sh
35+
poetry shell
36+
```
37+
38+
### Name your project
39+
40+
```sh
41+
invoke rename-project <your-project-name>
42+
```
43+
44+
### Run Code
45+
46+
To run your code, use the following command:
47+
48+
```sh
49+
poetry run invoke run
50+
```
51+
52+
### Run Tests
53+
54+
To run your tests, use the following command:
55+
56+
```sh
57+
poetry run invoke test
58+
```
59+
60+
### Run Formatters
61+
62+
To run the code formatters, use the following command:
63+
64+
```sh
65+
poetry run invoke format_code
66+
```
67+
68+
### Run Checking Code Style & Type hint
69+
70+
To check your code style and type hints, use the following command:
71+
72+
```sh
73+
poetry run invoke check
74+
```

monkey_patch_invoke.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import inspect
2+
import types
3+
from typing import Any, Callable, Dict, List, Tuple, Union
4+
5+
from invoke.context import Context
6+
from invoke.tasks import NO_DEFAULT, Task
7+
8+
9+
def monkey_patch_invoke() -> None:
10+
11+
def _patched_argspec(
12+
self: Any, # pylint: disable=unused-argument
13+
body: Union[Callable[[Context], None], Context],
14+
) -> Tuple[List[str], Dict[str, object]]:
15+
"""
16+
A monkey patching code for supporting python3
17+
from: https://github.com/pyinvoke/invoke/issues/357#issuecomment-1250744013
18+
"""
19+
signature: inspect.Signature = inspect.Signature()
20+
if isinstance(body, types.FunctionType):
21+
signature = inspect.signature(body)
22+
elif isinstance(body, types.MethodType):
23+
signature = inspect.signature(body.__call__)
24+
25+
parameter_names = [name for name, _ in signature.parameters.items()]
26+
argument_specs: dict[str, object] = {}
27+
for key, value in signature.parameters.items():
28+
value = value.default if not value.default == signature.empty else NO_DEFAULT
29+
argument_specs[key] = value
30+
31+
# Pop context argument
32+
try:
33+
context_arg = parameter_names.pop(0)
34+
except IndexError as error:
35+
raise TypeError('Tasks must have an initial Context argument!') from error
36+
37+
del argument_specs[context_arg]
38+
return parameter_names, argument_specs
39+
40+
Task.argspec = _patched_argspec
41+
42+
43+
monkey_patch_invoke()

poetry.lock

Lines changed: 1573 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

poetry.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[virtualenvs]
2+
create = true
3+
in-project = true

pyproject.toml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
[build-system]
2+
requires = ["poetry-core"]
3+
build-backend = "poetry.core.masonry.api"
4+
5+
[tool.poetry]
6+
name = "ygka"
7+
version = "0.0.0"
8+
description = ""
9+
authors = []
10+
readme = "README.md"
11+
12+
[tool.pyright]
13+
typeCheckingMode = "strict"
14+
15+
# Python environment settings
16+
pythonPlatform = "All"
17+
venvPath = "./.venv"
18+
stubPath = "./.type_stubs"
19+
include = ["./*"]
20+
exclude = ["**/node_modules", "**/__pycache__"]
21+
22+
# For untyped modules
23+
useLibraryCodeForTypes = true # Attempt to read and infer types from third-party modules if no stub files are present
24+
reportMissingTypeStubs = false # Ignore errors from modules without type stubs
25+
reportUnknownMemberType = false # Ignore errors from untyped function calls in third-party modules
26+
reportUnknownVariableType = false # Ignore errors from untyped function calls in third-party modules
27+
28+
pythonVersion = "3.9"
29+
30+
[tool.yapf]
31+
based_on_style = "pep8"
32+
spaces_before_comment = 2
33+
split_before_logical_operator = true
34+
column_limit = 119
35+
allow_split_before_dict_value = false
36+
37+
[tool.ruff]
38+
line-length = 119
39+
select = ["PLE", "PLR", "PLW", "E", "W", "F", "I", "Q", "C", "B"]
40+
41+
[tool.pytest.ini_options]
42+
addopts = ["--cov=ygka"]
43+
44+
45+
[tool.poetry.dependencies]
46+
python = "^3.9"
47+
poetry = "^1.4.0"
48+
49+
[tool.poetry.scripts]
50+
ygka = "ygka:main"
51+
52+
[tool.ruff.flake8-quotes]
53+
inline-quotes = "single"
54+
docstring-quotes = "single"
55+
multiline-quotes = "single"
56+
57+
[tool.poetry.group.dev.dependencies]
58+
toml = "^0.10.2"
59+
yapf = "^0.32.0"
60+
pytest = "^7.2.2"
61+
pytest-cov = "^4.0.0"
62+
invoke = "^1.7.3"
63+
ruff = "^0.0.199"
64+
types-invoke = "^1.7.3.16"
65+
types-toml = "^0.10.8.5"
66+
pyright = "^1.1.296"

tasks.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# type: ignore
2+
import shutil
3+
4+
import toml
5+
from invoke import Context, task
6+
from invoke.exceptions import UnexpectedExit
7+
8+
import monkey_patch_invoke as _ # noqa: F401
9+
10+
11+
def get_pep8_compliant_name(project_name: str) -> str:
12+
return project_name.replace('-', '_')
13+
14+
15+
def get_project_path():
16+
with open('pyproject.toml', encoding='utf-8') as file:
17+
data = toml.load(file)
18+
project_name = get_pep8_compliant_name(data['tool']['poetry']['name'])
19+
return project_name
20+
21+
22+
@task
23+
def run(context: Context):
24+
context.run(f'python -m {get_project_path()}', pty=True)
25+
26+
27+
@task
28+
def test(context: Context):
29+
context.run('pytest . --cov=. --cov-report=xml', pty=True)
30+
31+
32+
@task
33+
def format_code(context: Context, verbose: bool = False):
34+
commands = [
35+
f'pautoflake {get_project_path()}',
36+
f'ruff --fix {get_project_path()}',
37+
f'yapf --in-place --recursive --parallel {get_project_path()}',
38+
]
39+
40+
for command in commands:
41+
context.run(command, pty=True)
42+
43+
44+
@task
45+
def check(context: Context):
46+
check_code_style(context)
47+
check_types(context)
48+
49+
50+
@task
51+
def check_code_style(context: Context):
52+
commands = [
53+
f'ruff {get_project_path()}',
54+
f'yapf --diff --recursive --parallel {get_project_path()}',
55+
]
56+
57+
for command in commands:
58+
context.run(command, pty=True)
59+
60+
61+
@task
62+
def check_types(context: Context):
63+
context.run(f'pyright {get_project_path()}', pty=True)
64+
65+
66+
@task
67+
def rename_project(_context: Context, project_name: str):
68+
# Get the current project path
69+
current_project_path = get_project_path()
70+
71+
# Rename the directory
72+
shutil.move(get_pep8_compliant_name(current_project_path), get_pep8_compliant_name(project_name))
73+
74+
# Update the project name in pyproject.toml
75+
with open('pyproject.toml', 'r', encoding='utf-8') as file:
76+
data = toml.load(file)
77+
78+
data['tool']['poetry']['name'] = project_name
79+
80+
with open('pyproject.toml', 'w', encoding='utf-8') as file:
81+
toml.dump(data, file)
82+
83+
84+
@task
85+
def release(context: Context, version: str) -> None:
86+
'''Build & Publish to PyPI.'''
87+
88+
# load pyproject
89+
pyproject_path = 'pyproject.toml'
90+
pyproject_string = ''
91+
with open(pyproject_path, 'r', encoding='utf-8') as pyproject_file:
92+
pyproject_string = pyproject_file.read()
93+
pyproject = toml.loads(pyproject_string)
94+
# change version to today datetime
95+
pyproject['tool']['poetry']['version'] = version
96+
with open(pyproject_path, 'w', encoding='utf-8') as pyproject_file:
97+
toml.dump(pyproject, pyproject_file)
98+
99+
# build & publish
100+
try:
101+
context.run(
102+
'''
103+
poetry build --no-interaction
104+
poetry publish --no-interaction
105+
''',
106+
pty=True,
107+
)
108+
except UnexpectedExit as exception:
109+
with open(pyproject_path, 'w', encoding='utf-8') as pyproject_file:
110+
pyproject_file.write(pyproject_string)
111+
raise exception from exception
112+
113+
# recover to original
114+
with open(pyproject_path, 'w', encoding='utf-8') as pyproject_file:
115+
pyproject_file.write(pyproject_string)

ygka/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def main():
2+
print('Hello, World!')

ygka/__main__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import ygka
2+
3+
if __name__ == '__main__': # to make the project executable by `python3 -m ygka <query>`
4+
ygka.main()

ygka/tests/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)