kopia lustrzana https://github.com/jedie/PyInventory
commit
81d2a7f36e
2
.flake8
2
.flake8
|
@ -2,6 +2,6 @@
|
|||
# Move to pyproject.toml after: https://gitlab.com/pycqa/flake8/-/issues/428
|
||||
#
|
||||
[flake8]
|
||||
exclude = .pytest_cache, .tox, dist, htmlcov, */migrations/*, volumes
|
||||
exclude = .*, dist, htmlcov, */migrations/*, volumes
|
||||
#ignore = E402
|
||||
max-line-length = 119
|
||||
|
|
|
@ -1,41 +1,47 @@
|
|||
name: test
|
||||
# https://github.com/actions/setup-python
|
||||
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
schedule:
|
||||
- cron: '0 8 * * *'
|
||||
push:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: 'Python ${{ matrix.python-version }} on ${{ matrix.os }}'
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
PYTHONUNBUFFERED: 1
|
||||
strategy:
|
||||
max-parallel: 2
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: [3.9, 3.8, 3.7]
|
||||
os: [ubuntu-latest] # TODO: macOS-latest, windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v2
|
||||
- name: 'Set up Python ${{ matrix.python-version }}'
|
||||
uses: actions/setup-python@v1
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '${{ matrix.python-version }}'
|
||||
|
||||
- name: 'Install package'
|
||||
- name: 'Bootstrap'
|
||||
run: |
|
||||
pip3 install poetry
|
||||
make install
|
||||
python3 devshell.py quit
|
||||
|
||||
- name: 'List installed packages'
|
||||
run: |
|
||||
poetry run pip freeze
|
||||
python3 devshell.py list_venv_packages
|
||||
|
||||
- name: 'Run tests with Python v${{ matrix.python-version }}'
|
||||
run: |
|
||||
poetry run pytest
|
||||
python3 devshell.py pytest -vv
|
||||
|
||||
- name: 'Upload coverage report'
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
- name: 'Run linters'
|
||||
if: matrix.python-version == '3.8'
|
||||
run: |
|
||||
make lint
|
||||
python3 devshell.py linting
|
|
@ -1,4 +1,5 @@
|
|||
.*
|
||||
!.github
|
||||
!.flake8
|
||||
!.gitignore
|
||||
!.isort.cfg
|
||||
|
|
112
Makefile
112
Makefile
|
@ -1,112 +0,0 @@
|
|||
SHELL := /bin/bash
|
||||
MAX_LINE_LENGTH := 119
|
||||
export DJANGO_SETTINGS_MODULE ?= inventory_project.settings.local
|
||||
|
||||
all: help
|
||||
|
||||
help:
|
||||
@echo -e '_________________________________________________________________'
|
||||
@echo -e 'PyInventory - *dev* Makefile\n'
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9 -]+:.*?## / {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
|
||||
check-poetry:
|
||||
@if [[ "$(shell poetry --version 2>/dev/null)" == *"Poetry"* ]] ; \
|
||||
then \
|
||||
echo "Poetry found, ok." ; \
|
||||
else \
|
||||
echo 'Please install poetry first, with e.g.:' ; \
|
||||
echo 'make install-poetry' ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
|
||||
install-poetry: ## install or update poetry
|
||||
pip3 install -U pip
|
||||
pip3 install -U poetry
|
||||
|
||||
install: check-poetry ## install PyInventory via poetry
|
||||
poetry install
|
||||
|
||||
manage-update: ## Collectstatic + makemigration + migrate
|
||||
./manage.sh collectstatic --noinput
|
||||
./manage.sh makemigrations
|
||||
./manage.sh migrate
|
||||
|
||||
update: check-poetry ## update the sources and installation
|
||||
git fetch --all
|
||||
git pull origin master
|
||||
poetry run pip install -U pip
|
||||
poetry update
|
||||
|
||||
lint: ## Run code formatters and linter
|
||||
poetry run flynt -e "volumes" -e "htmlcov" --fail-on-change --line_length=${MAX_LINE_LENGTH} .
|
||||
poetry run isort --check-only .
|
||||
poetry run flake8 .
|
||||
|
||||
fix-code-style: ## Fix code formatting
|
||||
poetry run flynt -e "volumes" -e "htmlcov" --line_length=${MAX_LINE_LENGTH} .
|
||||
poetry run pyupgrade --exit-zero-even-if-changed --py3-plus --py36-plus --py37-plus `find . -name "*.py" -type f ! -path "./.tox/*" ! -path "./htmlcov/*" ! -path "*/volumes/*" 2>/dev/null`
|
||||
poetry run isort .
|
||||
poetry run autopep8 --aggressive --aggressive --in-place --recursive .
|
||||
|
||||
tox-listenvs: check-poetry ## List all tox test environments
|
||||
poetry run tox --listenvs
|
||||
|
||||
tox: check-poetry ## Run pytest via tox with all environments
|
||||
poetry run tox
|
||||
|
||||
tox-py36: check-poetry ## Run pytest via tox with *python v3.6*
|
||||
poetry run tox -e py36
|
||||
|
||||
tox-py37: check-poetry ## Run pytest via tox with *python v3.7*
|
||||
poetry run tox -e py37
|
||||
|
||||
tox-py38: check-poetry ## Run pytest via tox with *python v3.8*
|
||||
poetry run tox -e py38
|
||||
|
||||
pytest: check-poetry ## Run pytest
|
||||
poetry run pytest --workers auto --tests-per-worker 1
|
||||
|
||||
update-rst-readme: ## update README.rst from README.creole
|
||||
poetry run update_rst_readme
|
||||
|
||||
publish: ## Release new version to PyPi
|
||||
poetry run publish
|
||||
|
||||
run-dev-server: ## Run the django dev server in endless loop.
|
||||
./manage.sh collectstatic --noinput --link
|
||||
./manage.sh migrate
|
||||
./manage.sh runserver
|
||||
|
||||
createsuperuser: ## Create super user
|
||||
./manage.sh createsuperuser
|
||||
|
||||
messages: ## Make and compile locales message files
|
||||
./manage.sh makemessages --all --no-location --no-obsolete --ignore=htmlcov --ignore=.tox --ignore=volumes
|
||||
./manage.sh compilemessages -v 0
|
||||
|
||||
##############################################################################
|
||||
|
||||
dbbackup: ## Backup database
|
||||
./manage.sh dbbackup
|
||||
|
||||
dbrestore: ## Restore a database backup
|
||||
./manage.sh dbrestore
|
||||
|
||||
##############################################################################
|
||||
|
||||
run-docker-dev-server: ## Start docker containers with current dev source code
|
||||
rm -Rf dist/
|
||||
poetry build
|
||||
rm -Rf deployment/dist/
|
||||
cp -ruv dist deployment/
|
||||
cd deployment && make down
|
||||
cd deployment && ./compose.dev.sh pull
|
||||
cd deployment && ./compose.dev.sh build --pull
|
||||
cd deployment && ./compose.dev.sh up
|
||||
|
||||
shell_docker-dev-server: ## Go into bash shell in Django dev container
|
||||
cd deployment && ./compose.dev.sh exec django /bin/bash
|
||||
|
||||
##############################################################################
|
||||
|
||||
.PHONY: help install lint fix test publish
|
|
@ -54,60 +54,29 @@ This README contains only the information about local development installation.
|
|||
Read [[https://github.com/jedie/PyInventory/tree/master/deployment#readme|/deployment/README]] for instruction to install PyInventory on a root server.
|
||||
|
||||
|
||||
=== prepare
|
||||
|
||||
{{{
|
||||
~$ git clone https://github.com/jedie/PyInventory.git
|
||||
~$ cd PyInventory/
|
||||
~/PyInventory$ make
|
||||
_________________________________________________________________
|
||||
PyInventory - *dev* Makefile
|
||||
|
||||
install-poetry install or update poetry
|
||||
install install PyInventory via poetry
|
||||
manage-update Collectstatic + makemigration + migrate
|
||||
update update the sources and installation
|
||||
lint Run code formatters and linter
|
||||
fix-code-style Fix code formatting
|
||||
tox-listenvs List all tox test environments
|
||||
tox Run pytest via tox with all environments
|
||||
tox-py36 Run pytest via tox with *python v3.6*
|
||||
tox-py37 Run pytest via tox with *python v3.7*
|
||||
tox-py38 Run pytest via tox with *python v3.8*
|
||||
pytest Run pytest
|
||||
update-rst-readme update README.rst from README.creole
|
||||
publish Release new version to PyPi
|
||||
run-dev-server Run the django dev server in endless loop.
|
||||
createsuperuser Create super user
|
||||
messages Make and compile locales message files
|
||||
dbbackup Backup database
|
||||
dbrestore Restore a database backup
|
||||
run-docker-dev-server Start docker containers with current dev source code
|
||||
}}}
|
||||
|
||||
|
||||
=== local development installation
|
||||
|
||||
e.g.:
|
||||
{{{
|
||||
# install or update Poetry:
|
||||
~/PyInventory$ make install-poetry
|
||||
|
||||
# install PyInventory via poetry:
|
||||
~/PyInventory$ make install
|
||||
...
|
||||
|
||||
# Collectstatic + makemigration + migrate:
|
||||
~/PyInventory$ make manage-update
|
||||
|
||||
# Create a django super user:
|
||||
~/PyInventory$ ./manage.sh createsuperuser
|
||||
|
||||
# start local dev. web server:
|
||||
~/PyInventory$ make run-dev-server
|
||||
# Clone project (Use your fork SSH url!):
|
||||
~$ git clone https://github.com/jedie/PyInventory.git
|
||||
~$ cd PyInventory
|
||||
~/PyInventory$ ./devshell.py
|
||||
}}}
|
||||
|
||||
|
||||
Helpful for writing and debugging unittests is to run a local test server.
|
||||
e.g.:
|
||||
{{{
|
||||
~/PyInventory$ ./devshell.py run_testserver
|
||||
}}}
|
||||
The web page is available via: {{{http://127.0.0.1:8000/}}}
|
||||
|
||||
Call manage commands from test project, e.g.:
|
||||
{{{
|
||||
~/PyInventory$ ./devshell.py manage --help
|
||||
}}}
|
||||
|
||||
|
||||
=== local docker dev run
|
||||
|
||||
|
|
100
README.rst
100
README.rst
|
@ -90,61 +90,33 @@ This README contains only the information about local development installation.
|
|||
|
||||
Read `/deployment/README <https://github.com/jedie/PyInventory/tree/master/deployment#readme>`_ for instruction to install PyInventory on a root server.
|
||||
|
||||
prepare
|
||||
=======
|
||||
|
||||
::
|
||||
|
||||
~$ git clone https://github.com/jedie/PyInventory.git
|
||||
~$ cd PyInventory/
|
||||
~/PyInventory$ make
|
||||
_________________________________________________________________
|
||||
PyInventory - *dev* Makefile
|
||||
|
||||
install-poetry install or update poetry
|
||||
install install PyInventory via poetry
|
||||
manage-update Collectstatic + makemigration + migrate
|
||||
update update the sources and installation
|
||||
lint Run code formatters and linter
|
||||
fix-code-style Fix code formatting
|
||||
tox-listenvs List all tox test environments
|
||||
tox Run pytest via tox with all environments
|
||||
tox-py36 Run pytest via tox with *python v3.6*
|
||||
tox-py37 Run pytest via tox with *python v3.7*
|
||||
tox-py38 Run pytest via tox with *python v3.8*
|
||||
pytest Run pytest
|
||||
update-rst-readme update README.rst from README.creole
|
||||
publish Release new version to PyPi
|
||||
run-dev-server Run the django dev server in endless loop.
|
||||
createsuperuser Create super user
|
||||
messages Make and compile locales message files
|
||||
dbbackup Backup database
|
||||
dbrestore Restore a database backup
|
||||
run-docker-dev-server Start docker containers with current dev source code
|
||||
|
||||
local development installation
|
||||
==============================
|
||||
|
||||
e.g.:
|
||||
|
||||
::
|
||||
|
||||
# install or update Poetry:
|
||||
~/PyInventory$ make install-poetry
|
||||
|
||||
# install PyInventory via poetry:
|
||||
~/PyInventory$ make install
|
||||
...
|
||||
|
||||
# Collectstatic + makemigration + migrate:
|
||||
~/PyInventory$ make manage-update
|
||||
|
||||
# Create a django super user:
|
||||
~/PyInventory$ ./manage.sh createsuperuser
|
||||
|
||||
# start local dev. web server:
|
||||
~/PyInventory$ make run-dev-server
|
||||
# Clone project (Use your fork SSH url!):
|
||||
~$ git clone https://github.com/jedie/PyInventory.git
|
||||
~$ cd PyInventory
|
||||
~/PyInventory$ ./devshell.py
|
||||
|
||||
Helpful for writing and debugging unittests is to run a local test server.
|
||||
e.g.:
|
||||
|
||||
::
|
||||
|
||||
~/PyInventory$ ./devshell.py run_testserver
|
||||
|
||||
The web page is available via: ``http://127.0.0.1:8000/``
|
||||
|
||||
Call manage commands from test project, e.g.:
|
||||
|
||||
::
|
||||
|
||||
~/PyInventory$ ./devshell.py manage --help
|
||||
|
||||
local docker dev run
|
||||
====================
|
||||
|
||||
|
@ -244,17 +216,17 @@ Files are separated into: "/src/" and "/development/"
|
|||
history
|
||||
-------
|
||||
|
||||
* `compare v0.8.4...master <https://github.com/jedie/PyInventory/compare/v0.8.4...master>`_ **dev**
|
||||
* `compare v0.8.4...master <https://github.com/jedie/PyInventory/compare/v0.8.4...master>`_ **dev**
|
||||
|
||||
* tbc
|
||||
|
||||
* `v0.8.4 - 19.01.2021 <https://github.com/jedie/PyInventory/compare/v0.8.3...v0.8.4>`_
|
||||
* `v0.8.4 - 19.01.2021 <https://github.com/jedie/PyInventory/compare/v0.8.3...v0.8.4>`_
|
||||
|
||||
* Search items in change list by "kind" and "tags", too
|
||||
|
||||
* update requirements
|
||||
|
||||
* `v0.8.3 - 29.12.2020 <https://github.com/jedie/PyInventory/compare/v0.8.2...v0.8.3>`_
|
||||
* `v0.8.3 - 29.12.2020 <https://github.com/jedie/PyInventory/compare/v0.8.2...v0.8.3>`_
|
||||
|
||||
* update requirements
|
||||
|
||||
|
@ -262,11 +234,11 @@ history
|
|||
|
||||
* Small project setup changes
|
||||
|
||||
* `v0.8.2 - 20.12.2020 <https://github.com/jedie/PyInventory/compare/v0.8.1...v0.8.2>`_
|
||||
* `v0.8.2 - 20.12.2020 <https://github.com/jedie/PyInventory/compare/v0.8.1...v0.8.2>`_
|
||||
|
||||
* Bugfix `#33 <https://github.com/jedie/PyInventory/issues/33>`_: Upload images to new created Items
|
||||
|
||||
* `v0.8.1 - 09.12.2020 <https://github.com/jedie/PyInventory/compare/v0.8.0...v0.8.1>`_
|
||||
* `v0.8.1 - 09.12.2020 <https://github.com/jedie/PyInventory/compare/v0.8.0...v0.8.1>`_
|
||||
|
||||
* Fix migration: Don't create "/media/migrate.log" if there is nothing to migrate
|
||||
|
||||
|
@ -276,11 +248,11 @@ history
|
|||
|
||||
* update requirements
|
||||
|
||||
* `v0.8.0 - 06.12.2020 <https://github.com/jedie/PyInventory/compare/v0.7.0...v0.8.0>`_
|
||||
* `v0.8.0 - 06.12.2020 <https://github.com/jedie/PyInventory/compare/v0.7.0...v0.8.0>`_
|
||||
|
||||
* Outsource the "MEDIA file serve" part into `django.tools.serve_media_app <https://github.com/jedie/django-tools/tree/master/django_tools/serve_media_app#readme>`_
|
||||
|
||||
* `v0.7.0 - 23.11.2020 <https://github.com/jedie/PyInventory/compare/v0.6.0...v0.7.0>`_
|
||||
* `v0.7.0 - 23.11.2020 <https://github.com/jedie/PyInventory/compare/v0.6.0...v0.7.0>`_
|
||||
|
||||
* Change deployment setup:
|
||||
|
||||
|
@ -294,15 +266,15 @@ history
|
|||
|
||||
* pull all docker images before build
|
||||
|
||||
* `v0.6.0 - 15.11.2020 <https://github.com/jedie/PyInventory/compare/v0.5.0...v0.6.0>`_
|
||||
* `v0.6.0 - 15.11.2020 <https://github.com/jedie/PyInventory/compare/v0.5.0...v0.6.0>`_
|
||||
|
||||
* User can store images to every item: The image can only be accessed by the same user.
|
||||
|
||||
* `v0.5.0 - 14.11.2020 <https://github.com/jedie/PyInventory/compare/v0.4.2...v0.5.0>`_
|
||||
* `v0.5.0 - 14.11.2020 <https://github.com/jedie/PyInventory/compare/v0.4.2...v0.5.0>`_
|
||||
|
||||
* Merge separate git branches into one: "/src/" and "/development/" `#19 <https://github.com/jedie/PyInventory/issues/19>`_
|
||||
|
||||
* `v0.4.2 - 13.11.2020 <https://github.com/jedie/PyInventory/compare/v0.4.1...v0.4.2>`_
|
||||
* `v0.4.2 - 13.11.2020 <https://github.com/jedie/PyInventory/compare/v0.4.1...v0.4.2>`_
|
||||
|
||||
* Serve static files by Caddy
|
||||
|
||||
|
@ -310,11 +282,11 @@ history
|
|||
|
||||
* reduce CKEditor plugins
|
||||
|
||||
* `v0.4.1 - 2.11.2020 <https://github.com/jedie/PyInventory/compare/v0.4.0...v0.4.1>`_
|
||||
* `v0.4.1 - 2.11.2020 <https://github.com/jedie/PyInventory/compare/v0.4.0...v0.4.1>`_
|
||||
|
||||
* Small bugfixes
|
||||
|
||||
* `v0.4.0 - 1.11.2020 <https://github.com/jedie/PyInventory/compare/v0.3.2...v0.4.0>`_
|
||||
* `v0.4.0 - 1.11.2020 <https://github.com/jedie/PyInventory/compare/v0.3.2...v0.4.0>`_
|
||||
|
||||
* Move docker stuff and production use information into separate git branch
|
||||
|
||||
|
@ -322,11 +294,11 @@ history
|
|||
|
||||
* Add django-processinfo: collect information about the running server processes
|
||||
|
||||
* `v0.3.2 - 26.10.2020 <https://github.com/jedie/PyInventory/compare/v0.3.0...v0.3.2>`_
|
||||
* `v0.3.2 - 26.10.2020 <https://github.com/jedie/PyInventory/compare/v0.3.0...v0.3.2>`_
|
||||
|
||||
* Bugfix missing translations
|
||||
|
||||
* `v0.3.0 - 26.10.2020 <https://github.com/jedie/PyInventory/compare/v0.2.0...v0.3.0>`_
|
||||
* `v0.3.0 - 26.10.2020 <https://github.com/jedie/PyInventory/compare/v0.2.0...v0.3.0>`_
|
||||
|
||||
* setup production usage:
|
||||
|
||||
|
@ -344,7 +316,7 @@ history
|
|||
|
||||
* Bugfix for using manage commands ``dumpdata`` and ``loaddata``
|
||||
|
||||
* `v0.2.0 - 24.10.2020 <https://github.com/jedie/PyInventory/compare/v0.1.0...v0.2.0>`_
|
||||
* `v0.2.0 - 24.10.2020 <https://github.com/jedie/PyInventory/compare/v0.1.0...v0.2.0>`_
|
||||
|
||||
* Simplify item change list by nested item
|
||||
|
||||
|
@ -356,7 +328,7 @@ history
|
|||
|
||||
* Add docker-compose usage
|
||||
|
||||
* `v0.1.0 - 17.10.2020 <https://github.com/jedie/PyInventory/compare/v0.0.1...v0.1.0>`_
|
||||
* `v0.1.0 - 17.10.2020 <https://github.com/jedie/PyInventory/compare/v0.0.1...v0.1.0>`_
|
||||
|
||||
* Enhance models, admin and finish project setup
|
||||
|
||||
|
@ -399,4 +371,4 @@ donation
|
|||
|
||||
------------
|
||||
|
||||
``Note: this file is generated from README.creole 2021-01-19 19:10:25 with "python-creole"``
|
||||
``Note: this file is generated from README.creole 2021-04-05 20:00:43 with "python-creole"``
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
"""
|
||||
Helpter
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import ckeditor
|
||||
|
||||
|
||||
ckeditor_path = Path(ckeditor.__file__).parent
|
||||
print('Django-CKEditor path:', ckeditor_path)
|
||||
|
||||
build_config_path = Path(ckeditor_path, 'static/ckeditor/ckeditor/build-config.js')
|
||||
print('Build config:', build_config_path)
|
||||
|
||||
plugins_path = Path(ckeditor_path, 'static/ckeditor/ckeditor/plugins')
|
||||
print('Plugin path:', plugins_path)
|
||||
|
||||
assert plugins_path.is_dir()
|
||||
|
||||
plugins = {item.name for item in plugins_path.iterdir() if item.is_dir()}
|
||||
|
||||
in_plugins = False
|
||||
with build_config_path.open('r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line == 'plugins : {':
|
||||
in_plugins = True
|
||||
continue
|
||||
|
||||
if in_plugins:
|
||||
if line == '},':
|
||||
break
|
||||
plugin_name = line.split(':', 1)[0].strip(" '")
|
||||
plugins.add(plugin_name)
|
||||
|
||||
print("'removePlugins': (")
|
||||
for plugin_name in sorted(plugins):
|
||||
print(f" '{plugin_name}',")
|
||||
print(')')
|
|
@ -1,59 +0,0 @@
|
|||
"""
|
||||
Auto fill "verbose_name" translations:
|
||||
Just copy the model field name as translation.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
BASE_PATH = Path(__file__).parent.parent
|
||||
|
||||
MESSAGE_MAP = {
|
||||
'id': 'ID',
|
||||
}
|
||||
|
||||
|
||||
def fill(po_file_path):
|
||||
old_content = []
|
||||
new_content = []
|
||||
with po_file_path.open('r') as f:
|
||||
for line in f:
|
||||
old_content.append(line)
|
||||
|
||||
if line.startswith('msgid "'):
|
||||
msgstr = ''
|
||||
msgid = line[7:-2]
|
||||
try:
|
||||
model, attribute, kind = msgid.strip().split('.')
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if kind == 'verbose_name':
|
||||
if attribute in MESSAGE_MAP:
|
||||
msgstr = MESSAGE_MAP[attribute]
|
||||
else:
|
||||
words = attribute.replace('_', ' ').split(' ')
|
||||
msgstr = ' '.join(i.capitalize() for i in words)
|
||||
elif kind == 'help_text':
|
||||
msgstr = ' ' # "hide" empty "help_text"
|
||||
|
||||
elif (line == 'msgstr ""\n' or line == 'msgstr " "\n') and msgstr:
|
||||
line = f'msgstr "{msgstr}"\n'
|
||||
|
||||
line = line.replace('Content Tonie', 'Content-Tonie')
|
||||
new_content.append(line)
|
||||
|
||||
if new_content == old_content:
|
||||
print('Nothing to do, ok.')
|
||||
return
|
||||
|
||||
with po_file_path.open('w') as f:
|
||||
f.write(''.join(new_content))
|
||||
|
||||
print(f'updated: {po_file_path}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for dir in ('de', 'en'):
|
||||
print('_' * 100)
|
||||
print(dir)
|
||||
fill(Path(BASE_PATH, f'inventory/locale/{dir}/LC_MESSAGES/django.po'))
|
|
@ -0,0 +1,140 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
developer shell
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Just call this file, and the magic happens ;)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import venv
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
try:
|
||||
import ensurepip # noqa
|
||||
except ModuleNotFoundError as err:
|
||||
print(err)
|
||||
print('-' * 100)
|
||||
print('Error: Pip not available!')
|
||||
print('Hint: "apt-get install python3-venv"\n')
|
||||
raise
|
||||
|
||||
|
||||
assert sys.version_info >= (3, 7), 'Python version is too old!'
|
||||
|
||||
|
||||
if sys.platform == 'win32': # wtf
|
||||
# Files under Windows, e.g.: .../.venv/Scripts/python3.exe
|
||||
BIN_NAME = 'Scripts'
|
||||
FILE_EXT = '.exe'
|
||||
else:
|
||||
# Files under Linux/Mac and all other than Windows, e.g.: .../.venv/bin/python3
|
||||
BIN_NAME = 'bin'
|
||||
FILE_EXT = ''
|
||||
|
||||
VENV_PATH = Path('.venv')
|
||||
BIN_PATH = VENV_PATH / BIN_NAME
|
||||
PYTHON_PATH = BIN_PATH / f'python3{FILE_EXT}'
|
||||
PIP_PATH = BIN_PATH / f'pip{FILE_EXT}'
|
||||
POETRY_PATH = BIN_PATH / f'poetry{FILE_EXT}'
|
||||
|
||||
DEP_LOCK_PATH = Path('poetry.lock')
|
||||
DEP_HASH_PATH = VENV_PATH / '.dep_hash'
|
||||
|
||||
# script file defined in pyproject.toml as [tool.poetry.scripts]
|
||||
# (Under Windows: ".exe" not added!)
|
||||
PROJECT_SHELL_SCRIPT = BIN_PATH / 'devshell'
|
||||
|
||||
|
||||
def get_dep_hash():
|
||||
""" Get SHA512 hash from poetry.lock content. """
|
||||
return hashlib.sha512(DEP_LOCK_PATH.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def store_dep_hash():
|
||||
""" Generate /.venv/.dep_hash """
|
||||
DEP_HASH_PATH.write_text(get_dep_hash())
|
||||
|
||||
|
||||
def venv_up2date():
|
||||
""" Is existing .venv is up-to-date? """
|
||||
if DEP_HASH_PATH.is_file():
|
||||
return DEP_HASH_PATH.read_text() == get_dep_hash()
|
||||
return False
|
||||
|
||||
|
||||
def verbose_check_call(*popen_args):
|
||||
popen_args = [str(arg) for arg in popen_args] # e.g.: Path() -> str for python 3.7
|
||||
print(f'\n+ {" ".join(popen_args)}\n')
|
||||
return subprocess.check_call(popen_args)
|
||||
|
||||
|
||||
def noop_signal_handler(signal_num, frame):
|
||||
"""
|
||||
Signal handler that does nothing: Used to ignore "Ctrl-C" signals
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) == 2 and argv[1] in ('--update', '--help'):
|
||||
parser = argparse.ArgumentParser(
|
||||
prog=Path(__file__).name,
|
||||
description='Developer shell',
|
||||
epilog='...live long and prosper...'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--update', default=False, action='store_true',
|
||||
help='Force create/upgrade virtual environment'
|
||||
)
|
||||
parser.add_argument(
|
||||
'command_args',
|
||||
nargs=argparse.ZERO_OR_MORE,
|
||||
help='arguments to pass to dev-setup shell/cli',
|
||||
)
|
||||
options = parser.parse_args(argv)
|
||||
force_update = options.update
|
||||
extra_args = argv[2:]
|
||||
else:
|
||||
force_update = False
|
||||
extra_args = argv[1:]
|
||||
|
||||
# Create virtual env in ".../.venv/":
|
||||
if not PYTHON_PATH.is_file() or force_update:
|
||||
print('Create virtual env here:', VENV_PATH.absolute())
|
||||
builder = venv.EnvBuilder(symlinks=True, upgrade=True, with_pip=True)
|
||||
builder.create(env_dir=VENV_PATH)
|
||||
|
||||
# install/update "pip" and "poetry":
|
||||
if not POETRY_PATH.is_file() or force_update:
|
||||
# Note: Under Windows pip.exe can't replace this own .exe file, so use the module way:
|
||||
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip')
|
||||
verbose_check_call(PIP_PATH, 'install', 'poetry')
|
||||
|
||||
# install via poetry, if:
|
||||
# 1. .venv not exists
|
||||
# 2. "--update" used
|
||||
# 3. poetry.lock file was changed
|
||||
if not PROJECT_SHELL_SCRIPT.is_file() or force_update or not venv_up2date():
|
||||
verbose_check_call(POETRY_PATH, 'install')
|
||||
store_dep_hash()
|
||||
|
||||
# The cmd2 shell should not abort on Ctrl-C => ignore "Interrupt from keyboard" signal:
|
||||
signal.signal(signal.SIGINT, noop_signal_handler)
|
||||
|
||||
# Run project cmd shell via "setup.py" entrypoint:
|
||||
# (Call it via python, because Windows sucks calling the file direct)
|
||||
try:
|
||||
verbose_check_call(PYTHON_PATH, PROJECT_SHELL_SCRIPT, *extra_args)
|
||||
except subprocess.CalledProcessError as err:
|
||||
sys.exit(err.returncode)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
Plik diff jest za duży
Load Diff
|
@ -3,6 +3,7 @@ name = "PyInventory"
|
|||
version = "0.8.4"
|
||||
description = "Web based management to catalog things including state and location etc. using Python/Django."
|
||||
authors = ["JensDiemer <git@jensdiemer.de>"]
|
||||
homepage = "https://github.com/jedie/PyInventory"
|
||||
packages = [
|
||||
{ include = "inventory", from = "src" },
|
||||
{ include = "inventory_project", from = "src" },
|
||||
|
@ -60,11 +61,12 @@ docker = ["docker-compose"]
|
|||
postgres = ["psycopg2-binary"]
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
dev_shell = "*" # https://github.com/jedie/dev-shell
|
||||
poetry-publish = "*" # https://github.com/jedie/poetry-publish
|
||||
python-creole = "*" # https://github.com/jedie/python-creole
|
||||
tox = "*"
|
||||
pytest = "*"
|
||||
pytest-randomly = "*"
|
||||
pytest-randomly = "!=3.6.0" # https://github.com/python-poetry/poetry/issues/2372#issuecomment-812558146
|
||||
pytest-cov = "*"
|
||||
pytest-django = "*"
|
||||
pytest-parallel = "*"
|
||||
|
@ -78,9 +80,9 @@ pyupgrade = "*"
|
|||
model_bakery = "*" # https://github.com/model-bakers/model_bakery
|
||||
|
||||
[tool.poetry.scripts]
|
||||
manage = "inventory_project.manage:main"
|
||||
update_rst_readme = "inventory_project.publish:update_readme"
|
||||
publish = "inventory_project.publish:publish"
|
||||
devshell = 'inventory_project.dev_shell:devshell_cmdloop'
|
||||
run_testserver = 'inventory_project.manage:start_test_server'
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
|
@ -98,7 +100,7 @@ exclude="*/htmlcov/*,*/migrations/*,*/volumes/*"
|
|||
atomic=true
|
||||
line_length=120
|
||||
case_sensitive=false
|
||||
skip_glob=["*/htmlcov/*","*/migrations/*","*/volumes/*"]
|
||||
skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/volumes/*"]
|
||||
multi_line_output=3
|
||||
include_trailing_comma=true
|
||||
known_first_party=["inventory","inventory_project","inventory_tests"]
|
||||
|
@ -108,6 +110,10 @@ sections=["FUTURE","STDLIB","THIRDPARTY","FIRSTPARTY","LOCALFOLDER"]
|
|||
lines_after_imports=2
|
||||
|
||||
|
||||
[tool.coverage.run]
|
||||
omit = [".*"]
|
||||
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
# https://docs.pytest.org/en/latest/customize.html#pyproject-toml
|
||||
minversion = "6.0"
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import os
|
||||
|
||||
from django.core.management import BaseCommand, call_command
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Run Django dev. Server"
|
||||
|
||||
def verbose_call(self, command, **kwargs):
|
||||
self.stdout.write("\n")
|
||||
self.stdout.write("_" * 79)
|
||||
self.stdout.write(self.style.NOTICE(f" *** call '{command}' command:"))
|
||||
self.stdout.write("\n")
|
||||
call_command(command, **kwargs)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""
|
||||
INFO: The django reloader will call this multiple times!
|
||||
We check RUN_MAIN, that will be set in django.utils.autoreload
|
||||
So we can skip the first migrate run.
|
||||
"""
|
||||
if os.environ.get("RUN_MAIN"):
|
||||
self.verbose_call("migrate", run_syncdb=True, interactive=False, verbosity=1)
|
||||
self.verbose_call("showmigrations", verbosity=1)
|
||||
|
||||
self.verbose_call("runserver", use_threading=True, use_reloader=True, verbosity=2)
|
|
@ -1,15 +0,0 @@
|
|||
"""
|
||||
Just print version line on every call from commandline ;)
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
from django import __version__ as django_version
|
||||
|
||||
from inventory import __version__
|
||||
|
||||
|
||||
if __name__ == 'inventory_project':
|
||||
if '--version' not in sys.argv:
|
||||
print(f'PyInventory v{__version__} (Django v{django_version})', file=sys.stderr)
|
||||
print(f'DJANGO_SETTINGS_MODULE={os.environ["DJANGO_SETTINGS_MODULE"]!r}', file=sys.stderr)
|
|
@ -0,0 +1,228 @@
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import cmd2
|
||||
from creole.setup_utils import assert_rst_readme, update_rst_readme
|
||||
from dev_shell.base_cmd2_app import DevShellBaseApp
|
||||
from dev_shell.command_sets import DevShellBaseCommandSet
|
||||
from dev_shell.command_sets.dev_shell_commands import DevShellCommandSet as OriginDevShellCommandSet
|
||||
from dev_shell.command_sets.dev_shell_commands import run_linters
|
||||
from dev_shell.config import DevShellConfig
|
||||
from dev_shell.utils.assertion import assert_is_dir
|
||||
from dev_shell.utils.subprocess_utils import verbose_check_call
|
||||
from poetry_publish.publish import poetry_publish
|
||||
|
||||
import inventory
|
||||
|
||||
|
||||
PACKAGE_ROOT = Path(inventory.__file__).parent.parent.parent
|
||||
assert_is_dir(PACKAGE_ROOT / 'src' / 'inventory')
|
||||
|
||||
|
||||
def call_manage_py(*args):
|
||||
verbose_check_call('python3', '-m', 'inventory_project.manage.main', *args)
|
||||
|
||||
|
||||
@cmd2.with_default_category('PyInventory commands')
|
||||
class PyInventoryCommandSet(DevShellBaseCommandSet):
|
||||
def do_manage(self, statement: cmd2.Statement):
|
||||
"""
|
||||
Call PyInventory test "manage.py"
|
||||
"""
|
||||
call_manage_py(*statement.arg_list)
|
||||
|
||||
def do_run_testserver(self, statement: cmd2.Statement):
|
||||
"""
|
||||
Start Django dev server with the test project
|
||||
"""
|
||||
# Start the "[tool.poetry.scripts]" script via subprocess
|
||||
# This works good with django dev server reloads
|
||||
verbose_check_call('run_testserver', *statement.arg_list)
|
||||
|
||||
def do_makemessages(self, statement: cmd2.Statement):
|
||||
"""
|
||||
Make and compile locales message files
|
||||
"""
|
||||
call_manage_py(
|
||||
'makemessages',
|
||||
'--all',
|
||||
'--no-location', '--no-obsolete',
|
||||
'--ignore=htmlcov', '--ignore=.*'
|
||||
)
|
||||
call_manage_py(
|
||||
'compilemessages',
|
||||
'--ignore=htmlcov', '--ignore=.*'
|
||||
)
|
||||
|
||||
def do_update_rst_readme(self, statement: cmd2.Statement):
|
||||
"""
|
||||
update README.rst from README.creole
|
||||
"""
|
||||
update_rst_readme(
|
||||
package_root=PACKAGE_ROOT,
|
||||
filename='README.creole'
|
||||
)
|
||||
|
||||
def do_ckeditor_info(self, statement: cmd2.Statement):
|
||||
"""
|
||||
Print some information about CKEditor
|
||||
"""
|
||||
import ckeditor
|
||||
|
||||
ckeditor_path = Path(ckeditor.__file__).parent
|
||||
print('Django-CKEditor path:', ckeditor_path)
|
||||
|
||||
build_config_path = Path(ckeditor_path, 'static/ckeditor/ckeditor/build-config.js')
|
||||
print('Build config:', build_config_path)
|
||||
|
||||
plugins_path = Path(ckeditor_path, 'static/ckeditor/ckeditor/plugins')
|
||||
print('Plugin path:', plugins_path)
|
||||
|
||||
assert plugins_path.is_dir()
|
||||
|
||||
plugins = {item.name for item in plugins_path.iterdir() if item.is_dir()}
|
||||
|
||||
in_plugins = False
|
||||
with build_config_path.open('r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line == 'plugins : {':
|
||||
in_plugins = True
|
||||
continue
|
||||
|
||||
if in_plugins:
|
||||
if line == '},':
|
||||
break
|
||||
plugin_name = line.split(':', 1)[0].strip(" '")
|
||||
plugins.add(plugin_name)
|
||||
|
||||
print("'removePlugins': (")
|
||||
for plugin_name in sorted(plugins):
|
||||
print(f" '{plugin_name}',")
|
||||
print(')')
|
||||
|
||||
def do_fill_verbose_name_translations(self, statement: cmd2.Statement):
|
||||
"""
|
||||
Auto fill "verbose_name" translations:
|
||||
Just copy the model field name as translation.
|
||||
"""
|
||||
MESSAGE_MAP = {'id': 'ID'}
|
||||
|
||||
for lang_code in ('de', 'en'):
|
||||
print('_' * 100)
|
||||
print(lang_code)
|
||||
po_file_path = PACKAGE_ROOT / f'src/inventory/locale/{lang_code}/LC_MESSAGES/django.po'
|
||||
old_content = []
|
||||
new_content = []
|
||||
with po_file_path.open('r') as f:
|
||||
for line in f:
|
||||
old_content.append(line)
|
||||
|
||||
if line.startswith('msgid "'):
|
||||
msgstr = ''
|
||||
msgid = line[7:-2]
|
||||
try:
|
||||
model, attribute, kind = msgid.strip().split('.')
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if kind == 'verbose_name':
|
||||
if attribute in MESSAGE_MAP:
|
||||
msgstr = MESSAGE_MAP[attribute]
|
||||
else:
|
||||
words = attribute.replace('_', ' ').split(' ')
|
||||
msgstr = ' '.join(i.capitalize() for i in words)
|
||||
elif kind == 'help_text':
|
||||
msgstr = ' ' # "hide" empty "help_text"
|
||||
|
||||
elif (line == 'msgstr ""\n' or line == 'msgstr " "\n') and msgstr:
|
||||
line = f'msgstr "{msgstr}"\n'
|
||||
|
||||
line = line.replace('Content Tonie', 'Content-Tonie')
|
||||
new_content.append(line)
|
||||
|
||||
if new_content == old_content:
|
||||
print('Nothing to do, ok.')
|
||||
return
|
||||
|
||||
with po_file_path.open('w') as f:
|
||||
f.write(''.join(new_content))
|
||||
|
||||
print(f'updated: {po_file_path}')
|
||||
|
||||
|
||||
class DevShellCommandSet(OriginDevShellCommandSet):
|
||||
|
||||
# TODO:
|
||||
# pyupgrade --exit-zero-even-if-changed --py3-plus --py36-plus --py37-plus --py38-plus
|
||||
# `find . -name "*.py" -type f ! -path "./.tox/*" ! -path "./htmlcov/*" ! -path "*/volumes/*"
|
||||
|
||||
def do_publish(self, statement: cmd2.Statement):
|
||||
"""
|
||||
Publish "dev-shell" to PyPi
|
||||
"""
|
||||
# don't publish if README is not up-to-date:
|
||||
assert_rst_readme(package_root=PACKAGE_ROOT, filename='README.creole')
|
||||
|
||||
# don't publish if code style wrong:
|
||||
run_linters()
|
||||
|
||||
# don't publish if test fails:
|
||||
verbose_check_call('pytest', '-x')
|
||||
|
||||
poetry_publish(
|
||||
package_root=PACKAGE_ROOT,
|
||||
version=inventory.__version__,
|
||||
creole_readme=True # don't publish if README.rst is not up-to-date
|
||||
)
|
||||
|
||||
def do_linting(self, statement: cmd2.Statement):
|
||||
"""
|
||||
Linting: Check code style with flake8, isort and flynt
|
||||
"""
|
||||
verbose_check_call('flake8', exit_on_error=True)
|
||||
verbose_check_call(
|
||||
'isort', '--check-only', '.',
|
||||
exit_on_error=True
|
||||
)
|
||||
verbose_check_call(
|
||||
'flynt', '--fail-on-change', '--line_length=119', 'src',
|
||||
exit_on_error=True
|
||||
)
|
||||
|
||||
|
||||
class DevShellApp(DevShellBaseApp):
|
||||
pass
|
||||
|
||||
|
||||
def get_devshell_app_kwargs():
|
||||
"""
|
||||
Generate the kwargs for the cmd2 App.
|
||||
(Separated because we needs the same kwargs in tests)
|
||||
"""
|
||||
config = DevShellConfig(package_module=inventory)
|
||||
|
||||
# initialize all CommandSet() with context:
|
||||
kwargs = dict(
|
||||
config=config
|
||||
)
|
||||
|
||||
app_kwargs = dict(
|
||||
config=config,
|
||||
command_sets=[
|
||||
PyInventoryCommandSet(**kwargs),
|
||||
DevShellCommandSet(**kwargs),
|
||||
]
|
||||
)
|
||||
return app_kwargs
|
||||
|
||||
|
||||
def devshell_cmdloop():
|
||||
"""
|
||||
Entry point to start the "dev-shell" cmd2 app.
|
||||
Used in: [tool.poetry.scripts]
|
||||
"""
|
||||
c = DevShellApp(**get_devshell_app_kwargs())
|
||||
sys.exit(c.cmdloop())
|
|
@ -3,17 +3,21 @@ import os
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from django import __version__ as django_version
|
||||
|
||||
BASE_PATH = Path(__file__).parent
|
||||
import inventory
|
||||
from inventory import __version__
|
||||
|
||||
|
||||
BASE_PATH = Path(inventory.__file__).parent
|
||||
|
||||
|
||||
def main():
|
||||
assert 'DJANGO_SETTINGS_MODULE' in os.environ, 'No "DJANGO_SETTINGS_MODULE" in environment!'
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'inventory_project.settings.local')
|
||||
|
||||
# Change to /src/ and add it to sys.path
|
||||
src_path = Path(BASE_PATH, 'src').resolve()
|
||||
assert src_path.is_dir(), f'Path not exists: {src_path}'
|
||||
sys.path.insert(0, str(src_path))
|
||||
if '--version' not in sys.argv:
|
||||
print(f'PyInventory v{__version__} (Django v{django_version})', file=sys.stderr)
|
||||
print(f'DJANGO_SETTINGS_MODULE={os.environ["DJANGO_SETTINGS_MODULE"]!r}', file=sys.stderr)
|
||||
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
|
@ -31,5 +35,13 @@ def main():
|
|||
raise
|
||||
|
||||
|
||||
def start_test_server():
|
||||
"""
|
||||
Entrypoint for "[tool.poetry.scripts]" script started by devshell command.
|
||||
"""
|
||||
sys.argv = [__file__, "run_testserver"]
|
||||
main()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,7 +1,9 @@
|
|||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from dev_shell.utils.assertion import assert_is_file
|
||||
|
||||
import inventory
|
||||
|
||||
|
||||
|
@ -9,7 +11,6 @@ BASE_PATH = Path(inventory.__file__).parent.parent.parent
|
|||
|
||||
|
||||
def test_lint():
|
||||
assert Path(BASE_PATH, 'Makefile').is_file()
|
||||
make_bin = shutil.which('make')
|
||||
assert make_bin is not None
|
||||
subprocess.check_call([make_bin, 'lint'], cwd=BASE_PATH)
|
||||
dev_shell_py = BASE_PATH / 'devshell.py'
|
||||
assert_is_file(dev_shell_py)
|
||||
subprocess.check_call([sys.executable, str(dev_shell_py), 'linting'])
|
||||
|
|
Ładowanie…
Reference in New Issue