1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/pyinventory_ynh.git synced 2024-09-03 20:16:09 +02:00

Merge pull request #126 from YunoHost-Apps/dev

Dev
This commit is contained in:
Jens Diemer 2023-11-26 20:40:52 +01:00 committed by GitHub
commit 9364182dc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 455 additions and 564 deletions

View file

@ -31,7 +31,7 @@ This package for YunoHost used [django-yunohost-integration](https://github.com/
More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory
**Shipped version:** 0.19.3~ynh1 **Shipped version:** 0.19.3~ynh2
## Screenshots ## Screenshots

View file

@ -31,7 +31,7 @@ This package for YunoHost used [django-yunohost-integration](https://github.com/
More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory
**Version incluse :** 0.19.3~ynh1 **Version incluse :** 0.19.3~ynh2
## Captures décran ## Captures décran

View file

@ -16,9 +16,9 @@ bleach==6.1.0 \
--hash=sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe \ --hash=sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe \
--hash=sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6 --hash=sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6
# via django-tools # via django-tools
bx-django-utils==67 \ bx-django-utils==69 \
--hash=sha256:8740fdaf98ed68a8ddb3af025d9b4f87c99101405898ddca86810b0c384b215a \ --hash=sha256:39e96b8ad47bcf36d6713e4e42c8d09deb21e413160dc2944f17b7d2e2244713 \
--hash=sha256:aca0ae5c91a62e4f594172b8c43468c701516f99ae50d99412d5299ba375df03 --hash=sha256:59b806aa36b50184f14bd0f7a61fb66c478fa231a44f92472360ce0cf1616013
# via pyinventory # via pyinventory
bx-py-utils==88 \ bx-py-utils==88 \
--hash=sha256:32fbc7e9ff3dfb0a817c80fb1d165ec559643dab59c0be549e646acbf8223b75 \ --hash=sha256:32fbc7e9ff3dfb0a817c80fb1d165ec559643dab59c0be549e646acbf8223b75 \
@ -28,9 +28,9 @@ bx-py-utils==88 \
# cli-base-utilities # cli-base-utilities
# django-tools # django-tools
# pyinventory # pyinventory
certifi==2023.7.22 \ certifi==2023.11.17 \
--hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ --hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \
--hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 --hash=sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474
# via requests # via requests
charset-normalizer==3.3.2 \ charset-normalizer==3.3.2 \
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
@ -189,9 +189,9 @@ django-debug-toolbar==4.2.0 \
--hash=sha256:af99128c06e8e794479e65ab62cc6c7d1e74e1c19beb44dcbf9bad7a9c017327 \ --hash=sha256:af99128c06e8e794479e65ab62cc6c7d1e74e1c19beb44dcbf9bad7a9c017327 \
--hash=sha256:bc7fdaafafcdedefcc67a4a5ad9dac96efd6e41db15bc74d402a54a2ba4854dc --hash=sha256:bc7fdaafafcdedefcc67a4a5ad9dac96efd6e41db15bc74d402a54a2ba4854dc
# via pyinventory # via pyinventory
django-import-export==3.3.2 \ django-import-export==3.3.3 \
--hash=sha256:9a5c7c191014e4defb01573ee94864b60724a203f1b8a7e5e67a03f06b27b62d \ --hash=sha256:2c1b16e1cf2ea5f62a165d8867e7c6dcff25673ab7201fd18aaf67c9ee90367e \
--hash=sha256:d13e7508190f46442280bd7d04efcf49af6521350a70a6f9e06447ef28d6a41d --hash=sha256:78973202e93897326ab0411d64eaf89b72779fcb21ee9e5f64f3fb96571a5978
# via pyinventory # via pyinventory
django-js-asset==2.1.0 \ django-js-asset==2.1.0 \
--hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \ --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
@ -239,9 +239,9 @@ icdiff==2.0.7 \
--hash=sha256:f05d1b3623223dd1c70f7848da7d699de3d9a2550b902a8234d9026292fb5762 \ --hash=sha256:f05d1b3623223dd1c70f7848da7d699de3d9a2550b902a8234d9026292fb5762 \
--hash=sha256:f79a318891adbf59a45e3a7694f5e1f18c5407065264637072ac8363b759866f --hash=sha256:f79a318891adbf59a45e3a7694f5e1f18c5407065264637072ac8363b759866f
# via django-tools # via django-tools
idna==3.4 \ idna==3.6 \
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
# via requests # via requests
markdown-it-py==3.0.0 \ markdown-it-py==3.0.0 \
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
@ -342,9 +342,9 @@ psycopg2==2.9.9 \
--hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \ --hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \
--hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c --hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c
# via django-yunohost-integration # via django-yunohost-integration
pygments==2.16.1 \ pygments==2.17.2 \
--hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \ --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
--hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29 --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
# via rich # via rich
pyinventory==0.19.3 \ pyinventory==0.19.3 \
--hash=sha256:42e5710956e466df389ddf01c1ab8f9c432890b745a2a32765085c67fda78cfa \ --hash=sha256:42e5710956e466df389ddf01c1ab8f9c432890b745a2a32765085c67fda78cfa \
@ -420,9 +420,9 @@ requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
# via pyinventory # via pyinventory
rich==13.6.0 \ rich==13.7.0 \
--hash=sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245 \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \
--hash=sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235
# via # via
# cli-base-utilities # cli-base-utilities
# rich-click # rich-click
@ -446,17 +446,17 @@ tablib[html,ods,xls,xlsx,yaml]==3.5.0 \
# via # via
# django-import-export # django-import-export
# tablib # tablib
tomlkit==0.12.2 \ tomlkit==0.12.3 \
--hash=sha256:df32fab589a81f0d7dc525a4267b6d7a64ee99619cbd1eeb0fae32c1dd426977 \ --hash=sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4 \
--hash=sha256:eeea7ac7563faeab0a1ed8fe12c2e5a51c61f933f2502f7e9db0241a65163ad0 --hash=sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba
# via cli-base-utilities # via cli-base-utilities
typing-extensions==4.8.0 \ typing-extensions==4.8.0 \
--hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \
--hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef
# via rich-click # via rich-click
urllib3==2.0.7 \ urllib3==2.1.0 \
--hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \ --hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 \
--hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e --hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54
# via requests # via requests
webencodings==0.5.1 \ webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
@ -472,7 +472,7 @@ xlwt==1.3.0 \
# via tablib # via tablib
# The following packages are considered to be unsafe in a requirements file: # The following packages are considered to be unsafe in a requirements file:
setuptools==68.2.2 \ setuptools==69.0.2 \
--hash=sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87 \ --hash=sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2 \
--hash=sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a --hash=sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6
# via django-axes # via django-axes

View file

@ -1,8 +1,14 @@
from inventory.permissions import get_or_create_normal_user_group
def setup_project_user(user): def setup_project_user(user):
""" """
All users used the Django admin, so we need to set the "staff" user flag. All users used the Django admin, so we need to set the "staff" user flag.
Called from django_yunohost_integration.sso_auth Called from django_yunohost_integration.sso_auth
""" """
pyinventory_user_group = get_or_create_normal_user_group()[0]
user.groups.set([pyinventory_user_group])
user.is_staff = True user.is_staff = True
user.save() user.save()
return user return user

View file

@ -13,3 +13,48 @@ root@yunohost:~# /home/yunohost.app/pyinventory/manage.py sendtestemail --admins
How to debug a django YunoHost app, take a look into: How to debug a django YunoHost app, take a look into:
* https://github.com/YunoHost-Apps/django_example_ynh#developer-info * https://github.com/YunoHost-Apps/django_example_ynh#developer-info
## local test
For quicker developing of pyinventory_ynh in the context of YunoHost app,
it's possible to run the Django developer server with the settings
and urls made for YunoHost installation.
e.g.:
```bash
~$ git clone https://github.com/YunoHost-Apps/django_example.git
~$ cd pyinventory_ynh/
~/django_example$ ./dev-cli.py --help
```
The output will looks like:
[comment]: <> (✂✂✂ auto generated help start ✂✂✂)
```
Usage: ./dev-cli.py [OPTIONS] COMMAND [ARGS]...
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────╮
│ check-code-style Check code style by calling darker + flake8 │
│ coverage Run and show coverage. │
│ diffsettings Run "diffsettings" manage command against a "local_test" YunoHost │
│ installation. │
│ fix-code-style Fix code style of all pyinventory_ynh source code files via darker │
│ install Run pip-sync and install 'pyinventory_ynh' via pip as editable. │
│ local-test Build a "local_test" YunoHost installation and start the Django dev. │
│ server against it. │
│ mypy Run Mypy (configured in pyproject.toml) │
│ publish Build and upload this project to PyPi │
│ safety Run safety check against current requirements files │
│ test Compile YunoHost files and run Django unittests │
│ tox Run tox │
│ update Update "requirements*.txt" dependencies files │
│ update-test-snapshot-files Update all test snapshot files (by remove and recreate all snapshot │
│ files) │
│ version Print version and exit │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
```
[comment]: <> (✂✂✂ auto generated help end ✂✂✂)

View file

@ -5,7 +5,7 @@ id = "pyinventory"
name = "PyInventory" name = "PyInventory"
description.en = "Web based management to catalog things including state and location etc." description.en = "Web based management to catalog things including state and location etc."
version = "0.19.3~ynh1" version = "0.19.3~ynh2"
maintainers = ["Jens Diemer"] maintainers = ["Jens Diemer"]

View file

@ -3,5 +3,5 @@
Web based management to catalog things including state and location etc. Web based management to catalog things including state and location etc.
""" """
__version__ = '0.19.3+ynh1' __version__ = '0.19.3+ynh2'
__author__ = 'Jens Diemer <pyinventory_ynh@jensdiemer.de>' __author__ = 'Jens Diemer <pyinventory_ynh@jensdiemer.de>'

View file

@ -2,14 +2,17 @@
CLI for development CLI for development
""" """
import logging import logging
import os
import sys import sys
from pathlib import Path from pathlib import Path
import django
import rich_click as click import rich_click as click
from bx_py_utils.path import assert_is_file from bx_py_utils.path import assert_is_file
from cli_base.cli_tools.subprocess_utils import verbose_check_call from cli_base.cli_tools.subprocess_utils import verbose_check_call
from cli_base.cli_tools.version_info import print_version from cli_base.cli_tools.version_info import print_version
from django_yunohost_integration.local_test import create_local_test from django.core.management.commands.test import Command as DjangoTestCommand
from django_yunohost_integration.local_test import CreateResults, create_local_test
from manageprojects.utilities import code_style from manageprojects.utilities import code_style
from manageprojects.utilities.publish import publish_package from manageprojects.utilities.publish import publish_package
from rich import print # noqa; noqa from rich import print # noqa; noqa
@ -42,6 +45,7 @@ ARGUMENT_NOT_EXISTING_DIR = dict(
ARGUMENT_EXISTING_FILE = dict( ARGUMENT_EXISTING_FILE = dict(
type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, path_type=Path) type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, path_type=Path)
) )
CLI_EPILOG = 'Project Homepage: https://github.com/YunoHost-Apps/pyinventory_ynh'
class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier? class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier?
@ -50,10 +54,7 @@ class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier?
return super().make_context(info_name, *args, **kwargs) return super().make_context(info_name, *args, **kwargs)
@click.group( @click.group(cls=ClickGroup, epilog=CLI_EPILOG)
cls=ClickGroup,
epilog='Project Homepage: https://github.com/YunoHost-Apps/pyinventory_ynh',
)
def cli(): def cli():
pass pass
@ -76,7 +77,7 @@ def coverage(verbose: bool = True):
""" """
verbose_check_call('coverage', 'run', verbose=verbose, exit_on_error=True) verbose_check_call('coverage', 'run', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'combine', '--append', verbose=verbose, exit_on_error=True) verbose_check_call('coverage', 'combine', '--append', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'report', '--fail-under=30', verbose=verbose, exit_on_error=True) verbose_check_call('coverage', 'report', '--fail-under=10', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'xml', verbose=verbose, exit_on_error=True) verbose_check_call('coverage', 'xml', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'json', verbose=verbose, exit_on_error=True) verbose_check_call('coverage', 'json', verbose=verbose, exit_on_error=True)
@ -163,7 +164,10 @@ def publish():
""" """
Build and upload this project to PyPi Build and upload this project to PyPi
""" """
_run_unittest_cli(verbose=False, exit_after_run=False) # Don't publish a broken state try:
_run_django_test_cli() # Don't publish a broken state
except SystemExit as err:
assert err.code == 0, f'Exit code is not 0: {err.code}'
publish_package( publish_package(
module=pyinventory_ynh, module=pyinventory_ynh,
@ -217,64 +221,59 @@ def update_test_snapshot_files():
print(f'{removed_file_count} test snapshot files removed... run tests...') print(f'{removed_file_count} test snapshot files removed... run tests...')
# Just recreate them by running tests: # Just recreate them by running tests:
_run_unittest_cli( os.environ['RAISE_SNAPSHOT_ERRORS'] = '0' # Recreate snapshot files without error
extra_env=dict( try:
RAISE_SNAPSHOT_ERRORS='0', # Recreate snapshot files without error _run_django_test_cli()
), finally:
verbose=False, new_files = len(list(iter_snapshot_files()))
exit_after_run=False, print(f'{new_files} test snapshot files created, ok.\n')
)
new_files = len(list(iter_snapshot_files()))
print(f'{new_files} test snapshot files created, ok.\n')
cli.add_command(update_test_snapshot_files) cli.add_command(update_test_snapshot_files)
def _run_unittest_cli(extra_env=None, verbose=True, exit_after_run=True): def _run_django_test_cli():
""" """
Call the origin unittest CLI and pass all args to it. Call the origin Django test manage command CLI and pass all args to it.
""" """
if extra_env is None: os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
extra_env = dict()
extra_env.update( print('Compile YunoHost files...')
dict( result: CreateResults = create_local_test(
PYTHONUNBUFFERED='1', django_settings_path=PACKAGE_ROOT / 'conf' / 'settings.py',
PYTHONWARNINGS='always', destination=PACKAGE_ROOT / 'local_test',
) runserver=False,
extra_replacements={
'__DEBUG_ENABLED__': '0', # "1" or "0" string
'__LOG_LEVEL__': 'INFO',
'__ADMIN_EMAIL__': 'foo-bar@test.tld',
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
},
) )
print('Local test files created:')
print(result)
args = sys.argv[2:] data_dir = str(result.data_dir_path)
if not args: if data_dir not in sys.path:
if verbose: sys.path.insert(0, data_dir)
args = ('--verbose', '--locals', '--buffer')
else:
args = ('--locals', '--buffer')
verbose_check_call( django.setup()
sys.executable,
'-m', os.chdir(Path(pyinventory_ynh.__file__).parent)
'unittest',
*args, test_command = DjangoTestCommand()
timeout=15 * 60, test_command.run_from_argv(sys.argv)
extra_env=extra_env,
)
if exit_after_run:
sys.exit(0)
@click.command() # Dummy command @click.command() # Dummy command
def test(): def test():
""" """
Run unittests Compile YunoHost files and run Django unittests
""" """
_run_unittest_cli() _run_django_test_cli()
# TODO: Replace pytest with normal Django unittests: cli.add_command(test)
# cli.add_command(test)
def _run_tox(): def _run_tox():
@ -290,7 +289,7 @@ def tox():
_run_tox() _run_tox()
# TODO: cli.add_command(tox) cli.add_command(tox)
@click.command() @click.command()
@ -347,29 +346,19 @@ def diffsettings():
cli.add_command(diffsettings) cli.add_command(diffsettings)
@click.command()
def pytest():
"""
Run tests via "pytest"
"""
verbose_check_call(sys.executable, '-m', 'pytest', *sys.argv[2:], cwd=PACKAGE_ROOT)
cli.add_command(pytest)
def main(): def main():
print_version(pyinventory_ynh) print_version(pyinventory_ynh)
print(f'{sys.argv=}')
if len(sys.argv) >= 2: if len(sys.argv) >= 2:
# Check if we just pass a command call # Check if we just pass a command call
command = sys.argv[1] command = sys.argv[1]
if command == 'test': if command == 'test':
# TODO: Call: _run_unittest_cli() _run_django_test_cli()
verbose_check_call(sys.executable, '-m', 'pytest', cwd=PACKAGE_ROOT)
sys.exit(0) sys.exit(0)
elif command == 'tox': elif command == 'tox':
_run_tox() _run_tox()
sys.exit(0)
# Execute Click CLI: print('Execute Click CLI')
cli() cli()

View file

@ -1,7 +1,7 @@
from unittest.mock import patch from unittest.mock import patch
from axes.models import AccessLog from axes.models import AccessLog
from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin, assert_html_response_snapshot from bx_django_utils.test_utils.html_assertion import assert_html_response_snapshot, HtmlAssertionMixin
from django.conf import LazySettings, settings from django.conf import LazySettings, settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.template.defaulttags import CsrfTokenNode from django.template.defaulttags import CsrfTokenNode
@ -9,9 +9,7 @@ from django.test import override_settings
from django.test.testcases import TestCase from django.test.testcases import TestCase
from django.urls.base import reverse from django.urls.base import reverse
from django_yunohost_integration.test_utils import generate_basic_auth from django_yunohost_integration.test_utils import generate_basic_auth
from inventory import __version__ as upstream_version
import inventory
@override_settings(DEBUG=False) @override_settings(DEBUG=False)
class DjangoYnhTestCase(HtmlAssertionMixin, TestCase): class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
@ -29,10 +27,11 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
assert str(settings.DATA_DIR_PATH).endswith('/local_test/opt_yunohost') assert str(settings.DATA_DIR_PATH).endswith('/local_test/opt_yunohost')
assert str(settings.INSTALL_DIR_PATH).endswith('/local_test/var_www') assert str(settings.INSTALL_DIR_PATH).endswith('/local_test/var_www')
assert str(settings.LOG_FILE_PATH).endswith('/local_test/var_log_pyinventory.log') assert str(settings.LOG_FILE_PATH).endswith(
'/local_test/var_log_pyinventory.log'
), f'{settings.LOG_FILE_PATH=}'
assert settings.ROOT_URLCONF == 'urls' assert settings.ROOT_URLCONF == 'urls'
assert reverse('admin:index') == '/app_path/'
def test_config_panel_settings(self): def test_config_panel_settings(self):
# config_panel.toml settings, set via tests.conftest.pytest_configure(): # config_panel.toml settings, set via tests.conftest.pytest_configure():
@ -41,21 +40,9 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
assert settings.ADMIN_EMAIL == 'foo-bar@test.tld' assert settings.ADMIN_EMAIL == 'foo-bar@test.tld'
assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld' assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld'
def test_urls(self):
assert reverse('admin:index') == '/app_path/'
# Serve user uploads via django_tools.serve_media_app:
assert settings.MEDIA_URL == '/app_path/media/'
url = reverse(
'serve_media_app:serve-media',
kwargs={'user_token': 'token', 'path': 'foo/bar/'},
)
assert url == '/app_path/media/token/foo/bar/'
def test_auth(self): def test_auth(self):
assert settings.PATH_URL == 'app_path' self.assertEqual(settings.PATH_URL, 'app_path')
assert reverse('admin:index') == '/app_path/' self.assertEqual(reverse('admin:index'), '/app_path/')
# SecurityMiddleware should redirects all non-HTTPS requests to HTTPS: # SecurityMiddleware should redirects all non-HTTPS requests to HTTPS:
assert settings.SECURE_SSL_REDIRECT is True assert settings.SECURE_SSL_REDIRECT is True
@ -68,7 +55,11 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
) )
response = self.client.get('/app_path/', secure=True) response = self.client.get('/app_path/', secure=True)
self.assertRedirects(response, expected_url='/app_path/login/?next=/app_path/', fetch_redirect_response=False) self.assertRedirects(
response,
expected_url='/app_path/login/?next=%2Fapp_path%2F',
fetch_redirect_response=False,
)
def test_create_unknown_user(self): def test_create_unknown_user(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
@ -94,11 +85,16 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
self.assert_html_parts( self.assert_html_parts(
response, response,
parts=( parts=(
f'<title>Site administration | PyInventory v{inventory.__version__}</title>', f'<h1 id="site-name"><a href="/app_path/">PyInventory v{upstream_version}</a></h1>',
'<strong>test</strong>', '<strong>test</strong>',
#
# Can create PyInventory model entries:
'<a class="addlink" href="/app_path/inventory/itemmodel/add/">Add</a>',
'<a class="addlink" href="/app_path/inventory/locationmodel/add/">Add</a>',
'<a class="addlink" href="/app_path/inventory/memomodel/add/">Add</a>',
), ),
) )
assert_html_response_snapshot(response, query_selector='#container', validate=False) assert_html_response_snapshot(response, query_selector='#main', validate=False)
def test_wrong_auth_user(self): def test_wrong_auth_user(self):
assert User.objects.count() == 0 assert User.objects.count() == 0
@ -107,7 +103,7 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
self.client.cookies['SSOwAuthUser'] = 'test' self.client.cookies['SSOwAuthUser'] = 'test'
response = self.client.get( response = self.client.get(
path='/app_path/', path='/app_path/admin/',
HTTP_REMOTE_USER='test', HTTP_REMOTE_USER='test',
HTTP_AUTH_USER='foobar', # <<< wrong user name HTTP_AUTH_USER='foobar', # <<< wrong user name
HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz', HTTP_AUTHORIZATION='basic dGVzdDp0ZXN0MTIz',

View file

@ -0,0 +1,92 @@
<div class="main" id="main">
<div class="content" id="content-start" tabindex="-1">
<!-- Content -->
<div class="colMS" id="content">
<h1>
Site administration
</h1>
<div id="content-main">
<div class="app-inventory module">
<table>
<caption>
<a class="section" href="/app_path/inventory/" title="Models in the Inventory application">
Inventory
</a>
</caption>
<tr class="model-itemmodel">
<th scope="row">
<a href="/app_path/inventory/itemmodel/">
Items
</a>
</th>
<td>
<a class="addlink" href="/app_path/inventory/itemmodel/add/">
Add
</a>
</td>
<td>
<a class="changelink" href="/app_path/inventory/itemmodel/">
Change
</a>
</td>
</tr>
<tr class="model-locationmodel">
<th scope="row">
<a href="/app_path/inventory/locationmodel/">
Locations
</a>
</th>
<td>
<a class="addlink" href="/app_path/inventory/locationmodel/add/">
Add
</a>
</td>
<td>
<a class="changelink" href="/app_path/inventory/locationmodel/">
Change
</a>
</td>
</tr>
<tr class="model-memomodel">
<th scope="row">
<a href="/app_path/inventory/memomodel/">
Memos
</a>
</th>
<td>
<a class="addlink" href="/app_path/inventory/memomodel/add/">
Add
</a>
</td>
<td>
<a class="changelink" href="/app_path/inventory/memomodel/">
Change
</a>
</td>
</tr>
</table>
</div>
</div>
<div id="content-related">
<div class="module" id="recent-actions-module">
<h2>
Recent actions
</h2>
<h3>
My actions
</h3>
<p>
None available
</p>
</div>
</div>
<br class="clear"/>
</div>
<!-- END Content -->
<div id="footer">
<a href="https://github.com/jedie/PyInventory">
https://github.com/jedie/PyInventory
</a>
</div>
</div>
</div>

View file

@ -1,68 +1,104 @@
import subprocess import os
from unittest import TestCase
from bx_py_utils.path import assert_is_file
from manageprojects.test_utils.click_cli_utils import subprocess_cli
from manageprojects.test_utils.project_setup import check_editor_config, get_py_max_line_length
from manageprojects.utilities import code_style
from packaging.version import Version
from pyinventory_ynh import __version__
from pyinventory_ynh.cli.dev import PACKAGE_ROOT from pyinventory_ynh.cli.dev import PACKAGE_ROOT
try:
import tomllib # New in Python 3.11
except ImportError:
import tomli as tomllib
from bx_django_utils.filename import clean_filename
from bx_py_utils.path import assert_is_dir, assert_is_file
from django.test.testcases import TestCase
from django_tools.unittest_utils.project_setup import check_editor_config
from django_yunohost_integration.test_utils import assert_project_version
from inventory import __version__ as upstream_version
from pyinventory_ynh import __version__ as ynh_pkg_version
def assert_file_contains_string(file_path, string):
with file_path.open('r') as f:
for line in f:
if string in line:
return
raise AssertionError(f'File {file_path} does not contain {string!r} !')
class ProjectSetupTestCase(TestCase): class ProjectSetupTestCase(TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
manifest_path = PACKAGE_ROOT / 'manifest.toml'
assert_is_file(manifest_path)
cls.manifest_cfg = tomllib.loads(manifest_path.read_text(encoding='UTF-8'))
def test_version(self): def test_version(self):
self.assertIsNotNone(__version__) assert ynh_pkg_version.startswith(
upstream_version
), f'{ynh_pkg_version=} does not start with {upstream_version=}'
self.assertIn('+ynh', ynh_pkg_version)
version = Version(__version__) # Will raise InvalidVersion() if wrong formatted # pyproject.toml needs a PEP 440 conform version and used "+ynh"
self.assertEqual(str(version), __version__) # the YunoHost syntax is: "~ynh", just "convert this:
manifest_version = ynh_pkg_version.replace('+', '~')
self.assertEqual(self.manifest_cfg['version'], manifest_version)
dev_cli_bin = PACKAGE_ROOT / 'dev-cli.py' if 'GITHUB_ACTION' not in os.environ:
assert_is_file(dev_cli_bin) # Github has a rate-limiting... So don't fetch the API if we run as GitHub action
assert_project_version(
output = subprocess.check_output([dev_cli_bin, 'version'], text=True) current_version=ynh_pkg_version,
self.assertIn(f'pyinventory_ynh v{__version__}', output) github_project_url='https://github.com/jedie/PyInventory',
def test_code_style(self):
dev_cli_bin = PACKAGE_ROOT / 'dev-cli.py'
assert_is_file(dev_cli_bin)
try:
output = subprocess_cli(
cli_bin=dev_cli_bin,
args=('check-code-style',),
exit_on_error=False,
) )
except subprocess.CalledProcessError as err:
self.assertIn('.venv/bin/darker', err.stdout) # darker was called?
else:
if 'Code style: OK' in output:
self.assertIn('.venv/bin/darker', output) # darker was called?
return # Nothing to fix -> OK
# Try to "auto" fix code style: def test_screenshot_filenames(self):
"""
try: https://forum.yunohost.org/t/yunohost-bot-cant-handle-spaces-in-screenshots/19483
output = subprocess_cli( """
cli_bin=dev_cli_bin, screenshot_path = PACKAGE_ROOT / 'doc' / 'screenshots'
args=('fix-code-style',), assert_is_dir(screenshot_path)
exit_on_error=False, renamed = []
) for file_path in screenshot_path.iterdir():
except subprocess.CalledProcessError as err: file_name = file_path.name
output = err.stdout if file_name.startswith('.'):
continue
self.assertIn('.venv/bin/darker', output) # darker was called? cleaned_name = clean_filename(file_name)
if cleaned_name != file_name:
# Check again and display the output: new_path = file_path.with_name(cleaned_name)
file_path.rename(new_path)
try: renamed.append(f'{file_name!r} renamed to {cleaned_name!r}')
code_style.check(package_root=PACKAGE_ROOT) assert not renamed, f'Bad screenshots file names found: {", ".join(renamed)}'
except SystemExit as err:
self.assertEqual(err.code, 0, 'Code style error, see output above!')
def test_check_editor_config(self): def test_check_editor_config(self):
check_editor_config(package_root=PACKAGE_ROOT) check_editor_config(package_root=PACKAGE_ROOT)
max_line_length = get_py_max_line_length(package_root=PACKAGE_ROOT) def test_manifest_toml(self):
self.assertEqual(max_line_length, 119) self.assertEqual(self.manifest_cfg['packaging_format'], 2)
self.assertEqual(
set(self.manifest_cfg['install'].keys()),
{
'admin',
'admin_email',
'debug_enabled',
'default_from_email',
'domain',
'init_main_permission',
'log_level',
'path',
},
)
self.assertEqual(
set(self.manifest_cfg['resources'].keys()),
{
'apt',
'data_dir',
'database',
'install_dir',
'permissions',
'ports',
'system_user',
},
)

View file

@ -0,0 +1,36 @@
from pathlib import Path
from bx_py_utils.auto_doc import assert_readme_block
from manageprojects.test_utils.click_cli_utils import invoke_click
from manageprojects.tests.base import BaseTestCase
from pyinventory_ynh.cli.dev import CLI_EPILOG, PACKAGE_ROOT, cli
def assert_cli_help_in_readme(text_block: str, marker: str, readme_path: Path):
text_block = text_block.replace(CLI_EPILOG, '')
text_block = f'```\n{text_block.strip()}\n```'
assert_readme_block(
readme_path=readme_path,
text_block=text_block,
start_marker_line=f'[comment]: <> (✂✂✂ auto generated {marker} start ✂✂✂)',
end_marker_line=f'[comment]: <> (✂✂✂ auto generated {marker} end ✂✂✂)',
)
class ReadmeTestCase(BaseTestCase):
def test_main_help(self):
stdout = invoke_click(cli, '--help')
self.assert_in_content(
got=stdout,
parts=(
'Usage: ./dev-cli.py [OPTIONS] COMMAND [ARGS]...',
' local-test ',
CLI_EPILOG,
),
)
assert_cli_help_in_readme(
text_block=stdout,
marker='help',
readme_path=PACKAGE_ROOT / 'doc' / 'ADMIN.md',
)

View file

@ -25,14 +25,9 @@ dependencies = [
dev = [ dev = [
"bx_django_utils", # https://github.com/boxine/bx_django_utils "bx_django_utils", # https://github.com/boxine/bx_django_utils
"beautifulsoup4", # https://pypi.org/project/beautifulsoup4/ "beautifulsoup4", # https://pypi.org/project/beautifulsoup4/
#
# TODO: Remove "pytest" and use normal unittests ;)
"pytest",
"pytest-cov",
"pytest-django",
#
"manageprojects>=0.15.0", # https://github.com/jedie/manageprojects "manageprojects>=0.15.0", # https://github.com/jedie/manageprojects
"pip-tools", # https://github.com/jazzband/pip-tools/ "pip-tools", # https://github.com/jazzband/pip-tools/
"tblib", # https://github.com/ionelmc/python-tblib
"tox", # https://github.com/tox-dev/tox "tox", # https://github.com/tox-dev/tox
"coverage", # https://github.com/nedbat/coveragepy "coverage", # https://github.com/nedbat/coveragepy
"autopep8", # https://github.com/hhatto/autopep8 "autopep8", # https://github.com/hhatto/autopep8
@ -56,7 +51,6 @@ dev = [
# to avoid errors like: # to avoid errors like:
# In --require-hashes mode, all requirements must have their versions pinned with ==. These do not: ... # In --require-hashes mode, all requirements must have their versions pinned with ==. These do not: ...
"tomli", # Only needed for Python <3.11 "tomli", # Only needed for Python <3.11
"exceptiongroup", # needed by pytest
] ]
[project.urls] [project.urls]
@ -103,52 +97,23 @@ log_level = "INFO"
atomic=true atomic=true
profile='black' profile='black'
skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/local_test/*"] skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/local_test/*"]
known_first_party=['inventory', 'inventory_project', 'pyinventory_ynh'] known_first_party=['pyinventory', 'pyinventory_ynh']
line_length=119 line_length=119
lines_after_imports=2 lines_after_imports=2
[tool.pytest.ini_options]
# https://docs.pytest.org/en/latest/customize.html#pyproject-toml
minversion = "6.0"
norecursedirs = ".* .git __pycache__ conf local_test coverage* dist htmlcov"
# sometimes helpfull "addopts" arguments:
# -vv
# --verbose
# --capture=no
# --trace-config
# --full-trace
# -p no:warnings
addopts = """
--reuse-db
--nomigrations
--cov=.
--cov-config=pyproject.toml
--cov-report term-missing
--cov-report html
--cov-report xml
--no-cov-on-fail
--showlocals
--doctest-modules
--failed-first
--new-first
"""
[tool.coverage.run] [tool.coverage.run]
branch = true branch = true
parallel = true parallel = true
concurrency = ["multiprocessing"] concurrency = ["multiprocessing"]
source = ['.'] source = ['.']
# TODO: pytest -> Django unitests: command_line = './dev-cli.py test'
#command_line = '-m unittest --verbose --locals --buffer'
command_line = '-m pytest'
disable_warnings = ["couldnt-parse"] disable_warnings = ["couldnt-parse"]
[tool.coverage.report] [tool.coverage.report]
omit = ['.*', '*/tests/*'] omit = ['.*', '*/tests/*']
skip_empty = true skip_empty = true
fail_under = 30 fail_under = 10
show_missing = true show_missing = true
exclude_lines = [ exclude_lines = [
'if self.debug:', 'if self.debug:',
@ -216,4 +181,5 @@ applied_migrations = [
"0a5d693", # 2023-11-25T15:06:21+01:00 "0a5d693", # 2023-11-25T15:06:21+01:00
"6b89813", # 2023-11-25T15:23:07+01:00 "6b89813", # 2023-11-25T15:23:07+01:00
"4abd4c0", # 2023-11-25T15:59:31+01:00 "4abd4c0", # 2023-11-25T15:59:31+01:00
"2f9fd7b", # 2023-11-26T20:13:32+01:00
] ]

View file

@ -66,9 +66,9 @@ build==1.0.3 \
--hash=sha256:538aab1b64f9828977f84bc63ae570b060a8ed1be419e7870b8b4fc5e6ea553b \ --hash=sha256:538aab1b64f9828977f84bc63ae570b060a8ed1be419e7870b8b4fc5e6ea553b \
--hash=sha256:589bf99a67df7c9cf07ec0ac0e5e2ea5d4b37ac63301c4986d1acb126aa83f8f --hash=sha256:589bf99a67df7c9cf07ec0ac0e5e2ea5d4b37ac63301c4986d1acb126aa83f8f
# via pip-tools # via pip-tools
bx-django-utils==67 \ bx-django-utils==69 \
--hash=sha256:8740fdaf98ed68a8ddb3af025d9b4f87c99101405898ddca86810b0c384b215a \ --hash=sha256:39e96b8ad47bcf36d6713e4e42c8d09deb21e413160dc2944f17b7d2e2244713 \
--hash=sha256:aca0ae5c91a62e4f594172b8c43468c701516f99ae50d99412d5299ba375df03 --hash=sha256:59b806aa36b50184f14bd0f7a61fb66c478fa231a44f92472360ce0cf1616013
# via # via
# pyinventory # pyinventory
# pyinventory-ynh (pyproject.toml) # pyinventory-ynh (pyproject.toml)
@ -84,9 +84,9 @@ cachetools==5.3.2 \
--hash=sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2 \ --hash=sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2 \
--hash=sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1 --hash=sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1
# via tox # via tox
certifi==2023.7.22 \ certifi==2023.11.17 \
--hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ --hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \
--hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 --hash=sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474
# via requests # via requests
cffi==1.16.0 \ cffi==1.16.0 \
--hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
@ -273,11 +273,11 @@ colorlog==6.7.0 \
# via # via
# django-yunohost-integration # django-yunohost-integration
# pyinventory # pyinventory
cookiecutter==2.4.0 \ cookiecutter==2.5.0 \
--hash=sha256:6d1494e66a784f23324df9d593f3e43af3db4f4b926b9e49e6ff060169fc042a \ --hash=sha256:8aa2f12ed11bc05628651e9dc4353a10571dd9908aaaaeec959a2b9ea465a5d2 \
--hash=sha256:8344663028abc08ec09b912e663636a97e1775bffe973425ec0107431acd390e --hash=sha256:e61e9034748e3f41b8bd2c11f00d030784b48711c4d5c42363c50989a65331ec
# via manageprojects # via manageprojects
coverage[toml]==7.3.2 \ coverage==7.3.2 \
--hash=sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1 \ --hash=sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1 \
--hash=sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63 \ --hash=sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63 \
--hash=sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9 \ --hash=sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9 \
@ -330,9 +330,7 @@ coverage[toml]==7.3.2 \
--hash=sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738 \ --hash=sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738 \
--hash=sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a \ --hash=sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a \
--hash=sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4 --hash=sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4
# via # via pyinventory-ynh (pyproject.toml)
# pyinventory-ynh (pyproject.toml)
# pytest-cov
cryptography==41.0.5 \ cryptography==41.0.5 \
--hash=sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf \ --hash=sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf \
--hash=sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84 \ --hash=sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84 \
@ -417,9 +415,9 @@ django-debug-toolbar==4.2.0 \
--hash=sha256:af99128c06e8e794479e65ab62cc6c7d1e74e1c19beb44dcbf9bad7a9c017327 \ --hash=sha256:af99128c06e8e794479e65ab62cc6c7d1e74e1c19beb44dcbf9bad7a9c017327 \
--hash=sha256:bc7fdaafafcdedefcc67a4a5ad9dac96efd6e41db15bc74d402a54a2ba4854dc --hash=sha256:bc7fdaafafcdedefcc67a4a5ad9dac96efd6e41db15bc74d402a54a2ba4854dc
# via pyinventory # via pyinventory
django-import-export==3.3.2 \ django-import-export==3.3.3 \
--hash=sha256:9a5c7c191014e4defb01573ee94864b60724a203f1b8a7e5e67a03f06b27b62d \ --hash=sha256:2c1b16e1cf2ea5f62a165d8867e7c6dcff25673ab7201fd18aaf67c9ee90367e \
--hash=sha256:d13e7508190f46442280bd7d04efcf49af6521350a70a6f9e06447ef28d6a41d --hash=sha256:78973202e93897326ab0411d64eaf89b72779fcb21ee9e5f64f3fb96571a5978
# via pyinventory # via pyinventory
django-js-asset==2.1.0 \ django-js-asset==2.1.0 \
--hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \ --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
@ -471,10 +469,6 @@ et-xmlfile==1.1.0 \
--hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c \ --hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c \
--hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada --hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada
# via openpyxl # via openpyxl
exceptiongroup==1.1.3 \
--hash=sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9 \
--hash=sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3
# via pyinventory-ynh (pyproject.toml)
filelock==3.13.1 \ filelock==3.13.1 \
--hash=sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e \ --hash=sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e \
--hash=sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c --hash=sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c
@ -501,9 +495,9 @@ icdiff==2.0.7 \
--hash=sha256:f05d1b3623223dd1c70f7848da7d699de3d9a2550b902a8234d9026292fb5762 \ --hash=sha256:f05d1b3623223dd1c70f7848da7d699de3d9a2550b902a8234d9026292fb5762 \
--hash=sha256:f79a318891adbf59a45e3a7694f5e1f18c5407065264637072ac8363b759866f --hash=sha256:f79a318891adbf59a45e3a7694f5e1f18c5407065264637072ac8363b759866f
# via django-tools # via django-tools
idna==3.4 \ idna==3.6 \
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
# via requests # via requests
importlib-metadata==6.8.0 \ importlib-metadata==6.8.0 \
--hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \ --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \
@ -511,10 +505,6 @@ importlib-metadata==6.8.0 \
# via # via
# keyring # keyring
# twine # twine
iniconfig==2.0.0 \
--hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
--hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
# via pytest
isort==5.12.0 \ isort==5.12.0 \
--hash=sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504 \ --hash=sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504 \
--hash=sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6 --hash=sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6
@ -533,13 +523,13 @@ jinja2==3.1.2 \
--hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
--hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
# via cookiecutter # via cookiecutter
keyring==24.2.0 \ keyring==24.3.0 \
--hash=sha256:4901caaf597bfd3bbd78c9a0c7c4c29fcd8310dab2cffefe749e916b6527acd6 \ --hash=sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836 \
--hash=sha256:ca0746a19ec421219f4d713f848fa297a661a8a8c1504867e55bfb5e09091509 --hash=sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25
# via twine # via twine
manageprojects==0.15.2 \ manageprojects==0.15.3 \
--hash=sha256:44ac8973f9fede20693bd52c062d3b780268001f146100e6f3fc1bbaaa9ba720 \ --hash=sha256:052fe4e6ce8d2e36f9ec9adaffce918874512a96e3b92bc53a5cb3bfbf3ad3ad \
--hash=sha256:f264f238e5f2998019e2a654103c28519110c47d509ba9652b77883148fe3c85 --hash=sha256:4f94b261efc2013848043aaac7282f1496ef6207681a4a9881b67bdc5388140d
# via pyinventory-ynh (pyproject.toml) # via pyinventory-ynh (pyproject.toml)
markdown-it-py==3.0.0 \ markdown-it-py==3.0.0 \
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
@ -622,34 +612,34 @@ more-itertools==10.1.0 \
--hash=sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a \ --hash=sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a \
--hash=sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6 --hash=sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6
# via jaraco-classes # via jaraco-classes
mypy==1.6.1 \ mypy==1.7.1 \
--hash=sha256:19f905bcfd9e167159b3d63ecd8cb5e696151c3e59a1742e79bc3bcb540c42c7 \ --hash=sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340 \
--hash=sha256:21a1ad938fee7d2d96ca666c77b7c494c3c5bd88dff792220e1afbebb2925b5e \ --hash=sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49 \
--hash=sha256:40b1844d2e8b232ed92e50a4bd11c48d2daa351f9deee6c194b83bf03e418b0c \ --hash=sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82 \
--hash=sha256:41697773aa0bf53ff917aa077e2cde7aa50254f28750f9b88884acea38a16169 \ --hash=sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce \
--hash=sha256:49ae115da099dcc0922a7a895c1eec82c1518109ea5c162ed50e3b3594c71208 \ --hash=sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb \
--hash=sha256:4c46b51de523817a0045b150ed11b56f9fff55f12b9edd0f3ed35b15a2809de0 \ --hash=sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51 \
--hash=sha256:4cbe68ef919c28ea561165206a2dcb68591c50f3bcf777932323bc208d949cf1 \ --hash=sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5 \
--hash=sha256:4d01c00d09a0be62a4ca3f933e315455bde83f37f892ba4b08ce92f3cf44bcc1 \ --hash=sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e \
--hash=sha256:59a0d7d24dfb26729e0a068639a6ce3500e31d6655df8557156c51c1cb874ce7 \ --hash=sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7 \
--hash=sha256:68351911e85145f582b5aa6cd9ad666c8958bcae897a1bfda8f4940472463c45 \ --hash=sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33 \
--hash=sha256:7274b0c57737bd3476d2229c6389b2ec9eefeb090bbaf77777e9d6b1b5a9d143 \ --hash=sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9 \
--hash=sha256:81af8adaa5e3099469e7623436881eff6b3b06db5ef75e6f5b6d4871263547e5 \ --hash=sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1 \
--hash=sha256:82e469518d3e9a321912955cc702d418773a2fd1e91c651280a1bda10622f02f \ --hash=sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6 \
--hash=sha256:8b27958f8c76bed8edaa63da0739d76e4e9ad4ed325c814f9b3851425582a3cd \ --hash=sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a \
--hash=sha256:8c223fa57cb154c7eab5156856c231c3f5eace1e0bed9b32a24696b7ba3c3245 \ --hash=sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe \
--hash=sha256:8f57e6b6927a49550da3d122f0cb983d400f843a8a82e65b3b380d3d7259468f \ --hash=sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7 \
--hash=sha256:925cd6a3b7b55dfba252b7c4561892311c5358c6b5a601847015a1ad4eb7d332 \ --hash=sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200 \
--hash=sha256:a43ef1c8ddfdb9575691720b6352761f3f53d85f1b57d7745701041053deff30 \ --hash=sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7 \
--hash=sha256:a8032e00ce71c3ceb93eeba63963b864bf635a18f6c0c12da6c13c450eedb183 \ --hash=sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a \
--hash=sha256:b96ae2c1279d1065413965c607712006205a9ac541895004a1e0d4f281f2ff9f \ --hash=sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28 \
--hash=sha256:bb8ccb4724f7d8601938571bf3f24da0da791fe2db7be3d9e79849cb64e0ae85 \ --hash=sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea \
--hash=sha256:bbaf4662e498c8c2e352da5f5bca5ab29d378895fa2d980630656178bd607c46 \ --hash=sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120 \
--hash=sha256:cfd13d47b29ed3bbaafaff7d8b21e90d827631afda134836962011acb5904b71 \ --hash=sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d \
--hash=sha256:d4473c22cc296425bbbce7e9429588e76e05bc7342da359d6520b6427bf76660 \ --hash=sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42 \
--hash=sha256:d8fbb68711905f8912e5af474ca8b78d077447d8f3918997fecbf26943ff3cbb \ --hash=sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea \
--hash=sha256:e5012e5cc2ac628177eaac0e83d622b2dd499e28253d4107a08ecc59ede3fc2c \ --hash=sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2 \
--hash=sha256:eb4f18589d196a4cbe5290b435d135dee96567e07c2b2d43b5c4621b6501531a --hash=sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a
# via # via
# manageprojects # manageprojects
# pyinventory-ynh (pyproject.toml) # pyinventory-ynh (pyproject.toml)
@ -694,7 +684,6 @@ packaging==23.2 \
# dparse # dparse
# gunicorn # gunicorn
# pyproject-api # pyproject-api
# pytest
# safety # safety
# tox # tox
pathspec==0.11.2 \ pathspec==0.11.2 \
@ -765,9 +754,9 @@ pkginfo==1.9.6 \
--hash=sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546 \ --hash=sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546 \
--hash=sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046 --hash=sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046
# via twine # via twine
platformdirs==3.11.0 \ platformdirs==4.0.0 \
--hash=sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3 \ --hash=sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b \
--hash=sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e --hash=sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731
# via # via
# black # black
# tox # tox
@ -775,9 +764,7 @@ platformdirs==3.11.0 \
pluggy==1.3.0 \ pluggy==1.3.0 \
--hash=sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12 \ --hash=sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12 \
--hash=sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7 --hash=sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7
# via # via tox
# pytest
# tox
pprintpp==0.4.0 \ pprintpp==0.4.0 \
--hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \ --hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \
--hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403 --hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403
@ -815,9 +802,9 @@ pyflakes==3.1.0 \
# flake8 # flake8
# manageprojects # manageprojects
# pyinventory-ynh (pyproject.toml) # pyinventory-ynh (pyproject.toml)
pygments==2.16.1 \ pygments==2.17.2 \
--hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \ --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
--hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29 --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
# via # via
# darker # darker
# readme-renderer # readme-renderer
@ -834,21 +821,6 @@ pyproject-hooks==1.0.0 \
--hash=sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8 \ --hash=sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8 \
--hash=sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5 --hash=sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5
# via build # via build
pytest==7.4.3 \
--hash=sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac \
--hash=sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5
# via
# pyinventory-ynh (pyproject.toml)
# pytest-cov
# pytest-django
pytest-cov==4.1.0 \
--hash=sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6 \
--hash=sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a
# via pyinventory-ynh (pyproject.toml)
pytest-django==4.7.0 \
--hash=sha256:4e1c79d5261ade2dd58d91208017cd8f62cb4710b56e012ecd361d15d5d662a2 \
--hash=sha256:92d6fd46b1d79b54fb6b060bbb39428073396cec717d5f2e122a990d4b6aa5e8
# via pyinventory-ynh (pyproject.toml)
python-dateutil==2.8.2 \ python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
@ -951,9 +923,9 @@ rfc3986==2.0.0 \
--hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \
--hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c
# via twine # via twine
rich==13.6.0 \ rich==13.7.0 \
--hash=sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245 \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \
--hash=sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235
# via # via
# cli-base-utilities # cli-base-utilities
# cookiecutter # cookiecutter
@ -1052,6 +1024,10 @@ tablib[html,ods,xls,xlsx,yaml]==3.5.0 \
# via # via
# django-import-export # django-import-export
# tablib # tablib
tblib==3.0.0 \
--hash=sha256:80a6c77e59b55e83911e1e607c649836a69c103963c5f28a46cbeef44acf8129 \
--hash=sha256:93622790a0a29e04f0346458face1e144dc4d32f493714c6c3dff82a4adb77e6
# via pyinventory-ynh (pyproject.toml)
text-unidecode==1.3 \ text-unidecode==1.3 \
--hash=sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8 \ --hash=sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8 \
--hash=sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93 --hash=sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93
@ -1070,9 +1046,9 @@ tomli==2.0.1 \
# via # via
# flynt # flynt
# pyinventory-ynh (pyproject.toml) # pyinventory-ynh (pyproject.toml)
tomlkit==0.12.2 \ tomlkit==0.12.3 \
--hash=sha256:df32fab589a81f0d7dc525a4267b6d7a64ee99619cbd1eeb0fae32c1dd426977 \ --hash=sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4 \
--hash=sha256:eeea7ac7563faeab0a1ed8fe12c2e5a51c61f933f2502f7e9db0241a65163ad0 --hash=sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba
# via # via
# cli-base-utilities # cli-base-utilities
# manageprojects # manageprojects
@ -1094,23 +1070,23 @@ typing-extensions==4.8.0 \
# via # via
# mypy # mypy
# rich-click # rich-click
urllib3==2.0.7 \ urllib3==2.1.0 \
--hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \ --hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 \
--hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e --hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54
# via # via
# requests # requests
# twine # twine
virtualenv==20.24.6 \ virtualenv==20.24.7 \
--hash=sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af \ --hash=sha256:69050ffb42419c91f6c1284a7b24e0475d793447e35929b488bf6a0aade39353 \
--hash=sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381 --hash=sha256:a18b3fd0314ca59a2e9f4b556819ed07183b3e9a3702ecfe213f593d44f7b3fd
# via tox # via tox
webencodings==0.5.1 \ webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923
# via bleach # via bleach
wheel==0.41.3 \ wheel==0.42.0 \
--hash=sha256:488609bc63a29322326e05560731bf7bfea8e48ad646e1f5e40d366607de0942 \ --hash=sha256:177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d \
--hash=sha256:4d4987ce51a49370ea65c0bfd2234e8ce80a12780820d9dc462597a6e60d0841 --hash=sha256:c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7ceea617a8
# via pip-tools # via pip-tools
xlrd==2.0.1 \ xlrd==2.0.1 \
--hash=sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd \ --hash=sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd \
@ -1130,9 +1106,9 @@ pip==23.3.1 \
--hash=sha256:1fcaa041308d01f14575f6d0d2ea4b75a3e2871fe4f9c694976f908768e14174 \ --hash=sha256:1fcaa041308d01f14575f6d0d2ea4b75a3e2871fe4f9c694976f908768e14174 \
--hash=sha256:55eb67bb6171d37447e82213be585b75fe2b12b359e993773aca4de9247a052b --hash=sha256:55eb67bb6171d37447e82213be585b75fe2b12b359e993773aca4de9247a052b
# via pip-tools # via pip-tools
setuptools==68.2.2 \ setuptools==69.0.2 \
--hash=sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87 \ --hash=sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2 \
--hash=sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a --hash=sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6
# via # via
# django-axes # django-axes
# pip-tools # pip-tools

View file

View file

@ -1,43 +0,0 @@
"""
Special pytest init:
- Build a "local_test" YunoHost installation
- init Django with this local test installation
So the pytests will run against this local test installation
"""
import os
import sys
from pathlib import Path
import django
from django_yunohost_integration.local_test import CreateResults, create_local_test
BASE_PATH = Path(__file__).parent.parent
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
def pytest_configure():
print('Compile YunoHost files...')
result: CreateResults = create_local_test(
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
destination=BASE_PATH / 'local_test',
runserver=False,
extra_replacements={
'__DEBUG_ENABLED__': '0', # "1" or "0" string
'__LOG_LEVEL__': 'INFO',
'__ADMIN_EMAIL__': 'foo-bar@test.tld',
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
},
)
print('Local test files created:')
print(result)
os.chdir(result.data_dir_path)
data_dir = str(result.data_dir_path)
if data_dir not in sys.path:
sys.path.insert(0, data_dir)
django.setup()

View file

@ -1,92 +0,0 @@
<div id="container">
<!-- Header -->
<div id="header">
<div id="branding">
<h1 id="site-name">
<a href="/app_path/">
PyInventory v0.19.3
</a>
</h1>
</div>
<div id="user-tools">
Welcome,
<strong>
test
</strong>
.
<a href="/">
View site
</a>
/
<a href="/app_path/password_change/">
Change password
</a>
/
<form action="/app_path/logout/" id="logout-form" method="post">
MockedCsrfTokenNode
<button type="submit">
Log out
</button>
</form>
<button class="theme-toggle">
<div class="visually-hidden theme-label-when-auto">
Toggle theme (current theme: auto)
</div>
<div class="visually-hidden theme-label-when-light">
Toggle theme (current theme: light)
</div>
<div class="visually-hidden theme-label-when-dark">
Toggle theme (current theme: dark)
</div>
<svg aria-hidden="true" class="theme-icon-when-auto">
<use xlink:href="#icon-auto">
</use>
</svg>
<svg aria-hidden="true" class="theme-icon-when-dark">
<use xlink:href="#icon-moon">
</use>
</svg>
<svg aria-hidden="true" class="theme-icon-when-light">
<use xlink:href="#icon-sun">
</use>
</svg>
</button>
</div>
</div>
<!-- END Header -->
<div class="main" id="main">
<div class="content" id="content-start" tabindex="-1">
<!-- Content -->
<div class="colMS" id="content">
<h1>
Site administration
</h1>
<div id="content-main">
<p>
You dont have permission to view or edit anything.
</p>
</div>
<div id="content-related">
<div class="module" id="recent-actions-module">
<h2>
Recent actions
</h2>
<h3>
My actions
</h3>
<p>
None available
</p>
</div>
</div>
<br class="clear"/>
</div>
<!-- END Content -->
<div id="footer">
<a href="https://github.com/jedie/PyInventory">
https://github.com/jedie/PyInventory
</a>
</div>
</div>
</div>
</div>

View file

@ -1,108 +0,0 @@
import os
from pathlib import Path
from unittest import TestCase
try:
import tomllib # New in Python 3.11
except ImportError:
import tomli as tomllib
from bx_django_utils.filename import clean_filename
from bx_py_utils.path import assert_is_dir, assert_is_file
from django_tools.unittest_utils.project_setup import check_editor_config
from django_yunohost_integration.test_utils import assert_project_version
from inventory import __version__ as inventory_version
from pyinventory_ynh import __version__ as pyinventory_ynh_version
PACKAGE_ROOT = Path(__file__).parent.parent
def assert_file_contains_string(file_path, string):
with file_path.open('r') as f:
for line in f:
if string in line:
return
raise AssertionError(f'File {file_path} does not contain {string!r} !')
def test_version():
assert inventory_version in pyinventory_ynh_version, f'{inventory_version!r} not in {pyinventory_ynh_version!r}'
assert '+ynh' in pyinventory_ynh_version, f'{pyinventory_ynh_version!r} does not contain "+ynh"'
# pyproject.toml needs a PEP 440 conform version and used "+ynh"
# the YunoHost syntax is: "~ynh", just "convert this:
manifest_version = pyinventory_ynh_version.replace('+', '~')
assert_file_contains_string(
file_path=Path(PACKAGE_ROOT, 'manifest.toml'),
string=f'version = "{manifest_version}"',
)
if 'GITHUB_ACTION' not in os.environ:
# Github has a rate-limiting... So don't fetch the API if we run as GitHub action
assert_project_version(
current_version=inventory_version,
github_project_url='https://github.com/jedie/PyInventory',
)
def test_screenshot_filenames():
"""
https://forum.yunohost.org/t/yunohost-bot-cant-handle-spaces-in-screenshots/19483
"""
screenshot_path = PACKAGE_ROOT / 'doc' / 'screenshots'
assert_is_dir(screenshot_path)
renamed = []
for file_path in screenshot_path.iterdir():
file_name = file_path.name
if file_name.startswith('.'):
continue
cleaned_name = clean_filename(file_name)
if cleaned_name != file_name:
new_path = file_path.with_name(cleaned_name)
file_path.rename(new_path)
renamed.append(f'{file_name!r} renamed to {cleaned_name!r}')
assert not renamed, f'Bad screenshots file names found: {", ".join(renamed)}'
def test_check_editor_config():
check_editor_config(package_root=PACKAGE_ROOT)
class ManifestTestCase(TestCase):
def test_manifest_toml(self):
manifest_path = PACKAGE_ROOT / 'manifest.toml'
assert_is_file(manifest_path)
cfg = tomllib.loads(manifest_path.read_text(encoding='UTF-8'))
self.assertEqual(cfg['packaging_format'], 2)
self.assertEqual(
set(cfg['install'].keys()),
{
'admin',
'admin_email',
'debug_enabled',
'default_from_email',
'domain',
'init_main_permission',
'log_level',
'path',
},
)
self.assertEqual(
set(cfg['resources'].keys()),
{
'apt',
'data_dir',
'database',
'install_dir',
'permissions',
'ports',
'system_user',
},
)

View file

@ -1,8 +0,0 @@
from unittest.case import TestCase
from django_yunohost_integration.test_utils import generate_basic_auth
class TestUtilsTestCase(TestCase):
def test_generate_basic_auth(self):
assert generate_basic_auth(username='test', password='test123') == 'basic dGVzdDp0ZXN0MTIz'