-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
321 additions
and
359 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--- | ||
name: Bug report | ||
about: Create a report to help us improve | ||
title: "[BUG]" | ||
labels: bug | ||
assignees: '' | ||
|
||
--- | ||
|
||
**Describe the bug** | ||
A clear and concise description of what the bug is. | ||
|
||
**To Reproduce** | ||
Steps to reproduce the behavior: | ||
1. Install the *cookiecutter-python* package with *python3 -m pip install cookiecutter-python* | ||
2. Run the **cli** as: *generate-python ...* | ||
please provided the arguments supplied to the cli | ||
3. See error | ||
|
||
**Expected behavior** | ||
A clear and concise description of what you expected to happen. | ||
|
||
**Screenshots** | ||
If applicable, add screenshots to help explain your problem. | ||
|
||
**Desktop (please complete the following information):** | ||
- OS: [e.g. Linux Mint, iOS, Windows] | ||
- Version [e.g. 1.2.0] | ||
run: *generate-python --version* | ||
- Python Interpreter | ||
run: *generate-python --version* | ||
|
||
|
||
**Additional context** | ||
Add any other context about the problem here. | ||
For example, what input values were supplied to the *generate-python* | ||
cli (ie paste contents of your *config file*) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--- | ||
name: Feature request | ||
about: Suggest an idea for this project | ||
title: "[FEATURE]" | ||
labels: enhancement | ||
assignees: '' | ||
|
||
--- | ||
|
||
**Is your feature request related to a problem? Please describe.** | ||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] | ||
|
||
**Describe the solution you'd like** | ||
A clear and concise description of what you want to happen. | ||
|
||
**Describe alternatives you've considered** | ||
A clear and concise description of any alternative solutions or features you've considered. | ||
|
||
**Additional context** | ||
Add any other context or screenshots about the feature request here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--- | ||
name: Issue Inquiry | ||
about: Make an inquiry about an "issue" which is not a 'bug' nor a 'feature request' | ||
title: "[OTHER ISSUE]" | ||
labels: question | ||
assignees: '' | ||
|
||
--- | ||
|
||
**TODO: Title Goes Here** | ||
|
||
**Do you have a question related to the *cookiecutter-python* package?** | ||
Please submit your question :) | ||
|
||
Examples: | ||
- Why is *A* designed the way it is designed? | ||
- How does *A* accomplish whatever it accomplishes? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,4 @@ default_context: | |
author_email: [email protected] | ||
github_username: boromir674 | ||
project_short_description: Project generated from the https://github.com/boromir674/cookiecutter-python-package/tree/master/src/cookiecutter_python cookiecutter | ||
initialize_git_repo: yes | ||
initialize_git_repo: no |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ build-backend = "poetry.core.masonry.api" | |
## Also renders on pypi as 'subtitle' | ||
[tool.poetry] | ||
name = "cookiecutter_python" | ||
version = "1.2.0" | ||
version = "1.2.1" | ||
description = "Yet another modern Python Package (pypi) with emphasis in CI/CD and automation." | ||
authors = ["Konstantinos Lampridis <[email protected]>"] | ||
maintainers = ["Konstantinos Lampridis <[email protected]>"] | ||
|
@@ -190,3 +190,7 @@ hooks/post_gen_project.py | |
|
||
[tool.isort] | ||
profile = 'black' | ||
|
||
|
||
[tool.software-release] | ||
version_variable = "src/cookiecutter_python/__init__.py:__version__" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,126 @@ | ||
#!/usr/bin/env python | ||
|
||
|
||
import os | ||
import re | ||
import sys | ||
import typing as t | ||
|
||
# TODO Improve: try using the semantic_version_checker package for semver regex | ||
|
||
ExceptionFactory = t.Callable[[str, str, str], Exception] | ||
ClientCallback = t.Callable[[str, str], t.Tuple] | ||
|
||
MatchConverter = t.Callable[[t.Match], t.Tuple] | ||
MatchData = t.Tuple[str, t.List[t.Any], t.Callable[[t.Match], t.Tuple]] | ||
# 1st item (str): 'method'/'callable attribute' of the 're' python module) | ||
# 2nd item (list): zero or more additional runtime arguments | ||
# 3rd item (Callable): takes a Match object and return a tuple of strings | ||
|
||
my_dir = os.path.dirname(os.path.realpath(__file__)) | ||
|
||
SETUP_CFG_FILENAME = 'setup.cfg' | ||
SETUP_CFG = os.path.join(my_dir, '../', SETUP_CFG_FILENAME) | ||
TOML = 'pyproject.toml' | ||
TOML_FILE = os.path.abspath(os.path.join(my_dir, '..', TOML)) | ||
|
||
DEMO_SECTION: str = ( | ||
"[tool.software-release]\nversion_variable = " | ||
"src/package_name/__init__.py:__version__" | ||
) | ||
|
||
def main(): | ||
"""Get the package version string provided that the developer has setup indication how to find it. Reads the | ||
[semantic_release] section found in setup.cfg and then determines where is the actual version string | ||
""" | ||
# Automatically compute package version from the [semantic_release] section in setup.cfg | ||
with open(SETUP_CFG, 'r') as _file: | ||
regex = r"\[semantic_release\][\w\s=/\.:\d]+version_variable[\ \t]*=[\ \t]*([\w\.]+(?:/[\w\.]+)*):(\w+)" | ||
match = re.search(regex, _file.read(), re.MULTILINE) | ||
|
||
def build_client_callback(data: MatchData, factory: ExceptionFactory) -> ClientCallback: | ||
|
||
def client_callback(file_path: str, regex: str) -> t.Tuple: | ||
with open(file_path, 'r') as _file: | ||
contents = _file.read() | ||
match = getattr(re, data[0])(regex, contents, *data[1]) | ||
if match: | ||
file_with_version_string = os.path.join(my_dir, '../', match.group(1)) | ||
variable_holding_version_value = match.group(2) | ||
extracted_tuple = data[2](match) | ||
return extracted_tuple | ||
else: | ||
raise RuntimeError( | ||
f"Expected to find the '[semantic_release]' section, in the '{SETUP_CFG}' file, with key " | ||
f"'version_variable'.\nFor example:\n[semantic_release]\nversion_variable = " | ||
f"src/package_name/__init__.py:__version__\n indicated that the version string should be looked up in " | ||
f"the src/package_name/__init__.py file registered under the __version__ 'name'") | ||
|
||
# (it does not have to be a.py file) | ||
# to indicate that the version is stored in the '__version__' | ||
if not os.path.isfile(file_with_version_string): | ||
raise FileNotFoundError( | ||
f"Path '{file_with_version_string} does not appear to be valid. Please go to the '{SETUP_CFG}' file, at the" | ||
f" [semantic_release] section and set the 'version_variable' key with a valid file path (to look for the " | ||
f"version string)") | ||
raise factory(file_path, regex, contents) | ||
return client_callback | ||
|
||
reg_string = r'\s*=\s*[\'\"]([^\'\"]*)[\'\"]' | ||
|
||
# PARSERS | ||
|
||
with open(file_with_version_string, 'r') as _file: | ||
content = _file.read() | ||
reg = f'^{variable_holding_version_value}' + reg_string | ||
match = re.search(reg, content, re.MULTILINE) | ||
if match: | ||
_version = match.group(1) | ||
return _version | ||
raise AttributeError(f"Could not find a match for regex {reg} when applied to:\n{content}") | ||
software_release_parser = build_client_callback(( | ||
'search', | ||
[re.MULTILINE,], | ||
lambda match: (match.group(1), match.group(2)) | ||
), | ||
lambda file_path, reg, string: RuntimeError( | ||
"Expected to find the '[tool.software-release]' section, in " | ||
f"the '{file_path}' file, with key " | ||
"'version_variable'.\nFor example:\n" | ||
f"{DEMO_SECTION}\n " | ||
"indicates that the version string should be looked up in " | ||
f"the src/package_name/__init__.py file and specifically " | ||
"a '__version__ = 1.2.3' kind of line is expected to be found." | ||
) | ||
) | ||
|
||
|
||
if __name__ == '__main__': | ||
version_file_parser = build_client_callback(( | ||
'search', | ||
[re.MULTILINE,], | ||
lambda match: (match.group(1),) | ||
), | ||
lambda file_path, reg, string: AttributeError( | ||
"Could not find a match for regex {regex} when applied to:".format( | ||
regex=reg | ||
) + "\n{content}".format(content=string) | ||
) | ||
) | ||
|
||
|
||
def parse_version(software_release_cfg: str) -> str: | ||
"""Detect, parse and return the version (string) from python source code. | ||
Get the package version (string) provided that the developer has setup | ||
indication how to find it. | ||
Reads the [tool.software-release] section found in pyproject.toml and then | ||
determines where is the actual version string. | ||
""" | ||
header = r'\[tool\.software-release\]' | ||
sep = r'[\w\s=/\.:\d]+' # in some cases accounts for miss-typed characters! | ||
version_specification = \ | ||
r"version_variable[\ \t]*=[\ \t]*['\"]?([\w\.]+(?:/[\w\.]+)*):(\w+)['\"]?" | ||
regex = f"{header}{sep}{version_specification}" | ||
|
||
file_name_with_version, version_variable_name = \ | ||
software_release_parser(software_release_cfg, regex) | ||
|
||
file_with_version_string = \ | ||
os.path.abspath(os.path.join(my_dir, '../', file_name_with_version)) | ||
|
||
if not os.path.isfile(file_with_version_string): | ||
raise FileNotFoundError( | ||
f"Path '{file_with_version_string} does not appear to be valid. " | ||
f"Please go to the '{software_release_cfg}' file, at the" | ||
" [tool.software-release] section and set the 'version_variable' " | ||
"key with a valid file path (to look for the version string). " | ||
f"For example:\n{DEMO_SECTION}\n" | ||
) | ||
|
||
reg = f'^{version_variable_name}' + r'\s*=\s*[\'\"]([^\'\"]*)[\'\"]' | ||
version, = version_file_parser(file_with_version_string, reg) | ||
return version | ||
|
||
|
||
def _main(): | ||
try: | ||
version_string = main() | ||
version_string = parse_version(TOML_FILE) | ||
print(version_string) | ||
return 0 | ||
except (RuntimeError, FileNotFoundError, AttributeError) as exception: | ||
print(exception) | ||
sys.exit(1) | ||
return 1 | ||
|
||
|
||
def main(): | ||
sys.exit(_main()) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Oops, something went wrong.