14 Commits

Author SHA1 Message Date
github-actions[bot]
dd765ae981 chore(main): release 0.5.0 (#75)
🤖 I have created a release *beep* *boop*
---


## [0.5.0](https://github.com/shizand/statapp/compare/v0.4.2...v0.5.0)
(2023-10-06)


### Новые функции

* добавлен "Линейный полином"
([#74](https://github.com/shizand/statapp/issues/74))
([232de9f](232de9f145))


### Исправления

* добавлены переводы для QMessageBox
([#73](https://github.com/shizand/statapp/issues/73))
([e653c3d](e653c3df29))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-10-06 09:51:47 +03:00
bdb346fd17 ci: try fix ci 2023-10-06 09:44:00 +03:00
79297850df ci: try fix ci 2023-10-06 09:23:03 +03:00
232de9f145 feat: добавлен "Линейный полином" (#74) 2023-10-05 21:28:11 +03:00
e653c3df29 fix: добавлены переводы для QMessageBox (#73) 2023-10-05 21:27:51 +03:00
a89d7896e3 refactor: исправлены ВСЕ замечания pylint (#72) 2023-10-04 14:38:42 +03:00
d387a79d6d ci: fix version 2023-10-04 14:29:32 +03:00
dd3ab2e1cf ci: добавляет permissions для labeler 2023-10-04 14:21:58 +03:00
2115490b2c ci: добавляет labeler 2023-10-04 14:20:28 +03:00
d89837e34a chore: заменил codacy badge 2023-10-04 09:04:23 +03:00
af8d9cbdde chore: добавил too-few-public-methods 2023-10-04 09:02:24 +03:00
18157b9e82 chore: переименовал файл pylint 2023-10-04 08:55:13 +03:00
25bc63ee51 chore: добавлен pylint (#71) 2023-10-04 08:42:16 +03:00
fea99f0985 chore: добавлен файл README.md (#69)
Closes #26.

---------

Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com>
2023-10-03 20:49:35 +03:00
41 changed files with 889 additions and 229 deletions

View File

@@ -47,7 +47,7 @@ jobs:
- name: Установка зависимостей - name: Установка зависимостей
run: poetry install run: poetry install
- name: Сборка - name: Сборка
run: poetry run pyinstaller ${{ matrix.spec }}.spec\ run: poetry run pyinstaller statapp.spec -- -- ${{ matrix.spec == 'statapp-onefile' && '--one-file' || '' }}
- name: Архивация - name: Архивация
uses: thedoctor0/zip-release@0.7.1 uses: thedoctor0/zip-release@0.7.1
with: with:

31
.github/workflows/size-labeler.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: labeler
on: [pull_request]
jobs:
labeler:
runs-on: ubuntu-latest
name: Label the PR size
permissions:
issues: write
pull-requests: write
steps:
- uses: codelytv/pr-size-labeler@v1.7.0
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
xs_label: 'size/xs'
xs_max_size: '10'
s_label: 'size/s'
s_max_size: '100'
m_label: 'size/m'
m_max_size: '500'
l_label: 'size/l'
l_max_size: '1000'
xl_label: 'size/xl'
fail_if_xl: 'false'
message_if_xl: >
Этот PR превышает рекомендуемый размер в 1000 строк.
Пожалуйста, убедитесь, что вы НЕ решаете несколько проблем с помощью одного PR.
github_api_url: 'api.github.com'
files_to_ignore: |
"ui_*.py"

3
.idea/misc.xml generated
View File

@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="Black">
<option name="sdkName" value="Poetry (statapp)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (statapp)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Poetry (statapp)" project-jdk-type="Python SDK" />
</project> </project>

View File

@@ -1,5 +1,9 @@
# See https://pre-commit.com for more information # See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks # See https://pre-commit.com/hooks.html for more hooks
ci:
autofix_commit_msg: 'chore: [pre-commit.ci] auto fixes from pre-commit.com hooks'
autoupdate_commit_msg: 'chore: [pre-commit.ci] pre-commit autoupdate'
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0 rev: v3.2.0
@@ -14,3 +18,16 @@ repos:
- id: licenseheaders - id: licenseheaders
args: ["-t", ".copyright.tmpl", "-cy", "-f", "-d", "statapp"] args: ["-t", ".copyright.tmpl", "-cy", "-f", "-d", "statapp"]
pass_filenames: false pass_filenames: false
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
args:
[
"-rn", # Only display messages
"-sn", # Don't display the score
"--rcfile=.pylintrc",
]

24
.pylintrc Normal file
View File

@@ -0,0 +1,24 @@
[MAIN]
ignored-modules=PySide2
extension-pkg-whitelist=PySide2
[MASTER]
init-hook="import sys; sys.path.append('./statapp')"
ignore-patterns=ui_.+\.py
[BASIC]
attr-rgx=^_?[a-z][a-zA-Z0-9]+$|^_?[a-z0-9]+$|^_?[a-z0-9]+(_[a-z0-9]+)*$ # camelCase, lowercase, snake_case
class-attribute-rgx=^_?[a-z][a-zA-Z0-9]+$|^_?[a-z0-9]+$|^_?[a-z0-9]+(_[a-z0-9]+)*$ # camelCase, lowercase
variable-rgx=^_?[a-z][a-zA-Z0-9]+$|^_?[a-z0-9]+$ # camelCase, lowercase
argument-rgx=^_?[a-z][a-zA-Z0-9]+$|^_?[a-z0-9]+$ # camelCase, lowercase
function-rgx=^_?[a-z][a-zA-Z0-9]+$ # camelCase
method-rgx=^_?[a-z][a-zA-Z0-9]+$|^_?on_[a-z][a-zA-Z]+_[a-z][a-zA-Z]+|^__init__$ # camelCase, on_camelCaseWidget_camelCaseSignal and __init__
[MESSAGES CONTROL]
disable=
unused-argument,
fixme,
missing-docstring,
too-many-public-methods,
too-few-public-methods,
too-many-arguments

View File

@@ -1,5 +1,17 @@
# Changelog # Changelog
## [0.5.0](https://github.com/shizand/statapp/compare/v0.4.2...v0.5.0) (2023-10-06)
### Новые функции
* добавлен "Линейный полином" ([#74](https://github.com/shizand/statapp/issues/74)) ([232de9f](https://github.com/shizand/statapp/commit/232de9f145862a1a1e493478ba5fe8a6e4866e5a))
### Исправления
* добавлены переводы для QMessageBox ([#73](https://github.com/shizand/statapp/issues/73)) ([e653c3d](https://github.com/shizand/statapp/commit/e653c3df29355e84f5845d428d2265b902f5abeb))
## [0.4.2](https://github.com/shizand/statapp/compare/v0.4.1...v0.4.2) (2023-10-03) ## [0.4.2](https://github.com/shizand/statapp/compare/v0.4.1...v0.4.2) (2023-10-03)

View File

@@ -0,0 +1,56 @@
# Statapp
![Release info](https://img.shields.io/github/v/release/shizand/statapp)
![Python version](https://img.shields.io/badge/python-3.8-blue.svg)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/c4e370d74a8a4575b79afa8b9b74d130)](https://app.codacy.com/gh/shizand/statapp/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
![License info](https://img.shields.io/github/license/shizand/statapp)
Автоматизированное программное средство по статистическому анализу и регрессионному моделированию. Является идейным продолжателем программы STAT.exe (Produced by Reutov V.N., Donetsk University, 1990)
Разработано двумя студентами ФГБОУ ВО «ДонНТУ» для своего университета.
## Поддерживаемые ОС и архитектуры
В теории, должно работать на любой архитектуре и ОС где запускается Python 3.8 и есть Qt 5.
Работоспособность проверена на x64:
* на Windows 7, 10;
* на ALT Linux 10.2.
## Установка
Существует два варианта statapp и statapp-onefile. Различия в том, что onefile версия поставляется одним единственным бинарным файлом. На Windows системах с включенным антивирусом это может вызывать [некоторые проблемы](https://qna.habr.com/q/988553).
### Готовые двоичные файлы
[Скачайте архив](https://github.com/shizand/statapp/releases) под вашу платформу и распакуйте в любом месте.
### Сборка из исходников
В этом проекте используется [poetry](https://python-poetry.org/).
```bash
poetry install
pyinstaller statapp.spec # или pyinstaller statapp.spec -- --one-file
```
## Использование
<!-- TODO -->
## Чем я могу помочь проекту?
* [Сообщить об ошибке](https://github.com/shizand/statapp/issues/new?labels=%D0%B1%D0%B0%D0%B3)
## Исходный код
Исходный код доступен на [GitHub](https://github.com/shizand/statapp).
Также есть зеркала:
* [GitFic](https://gitflic.ru/project/shizand/statapp);
* [Gitea сервер](https://git.slipenko.com/shizand/statapp).
## Лицензия
[GPL-3.0 © Maxim Slipenko, Eugene Lazurenko.](https://github.com/shizand/statapp/blob/main/LICENSE)

277
poetry.lock generated
View File

@@ -11,6 +11,22 @@ files = [
{file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"}, {file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"},
] ]
[[package]]
name = "astroid"
version = "2.15.8"
description = "An abstract syntax tree for Python with inference support."
optional = false
python-versions = ">=3.7.2"
files = [
{file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"},
{file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"},
]
[package.dependencies]
lazy-object-proxy = ">=1.4.0"
typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""}
[[package]] [[package]]
name = "cfgv" name = "cfgv"
version = "3.4.0" version = "3.4.0"
@@ -22,6 +38,31 @@ files = [
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
] ]
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "dill"
version = "0.3.7"
description = "serialize all of Python"
optional = false
python-versions = ">=3.7"
files = [
{file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"},
{file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"},
]
[package.extras]
graph = ["objgraph (>=1.7.2)"]
[[package]] [[package]]
name = "distlib" name = "distlib"
version = "0.3.7" version = "0.3.7"
@@ -51,13 +92,13 @@ typing = ["typing-extensions (>=4.7.1)"]
[[package]] [[package]]
name = "identify" name = "identify"
version = "2.5.29" version = "2.5.30"
description = "File identification library for Python" description = "File identification library for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "identify-2.5.29-py2.py3-none-any.whl", hash = "sha256:24437fbf6f4d3fe6efd0eb9d67e24dd9106db99af5ceb27996a5f7895f24bf1b"}, {file = "identify-2.5.30-py2.py3-none-any.whl", hash = "sha256:afe67f26ae29bab007ec21b03d4114f41316ab9dd15aa8736a167481e108da54"},
{file = "identify-2.5.29.tar.gz", hash = "sha256:d43d52b86b15918c137e3a74fff5224f60385cd0e9c38e99d07c257f02f151a5"}, {file = "identify-2.5.30.tar.gz", hash = "sha256:f302a4256a15c849b91cfcdcec052a8ce914634b2f77ae87dad29cd749f2d88d"},
] ]
[package.extras] [package.extras]
@@ -82,6 +123,68 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker
perf = ["ipython"] perf = ["ipython"]
testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
[[package]]
name = "isort"
version = "5.12.0"
description = "A Python utility / library to sort Python imports."
optional = false
python-versions = ">=3.8.0"
files = [
{file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
{file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
]
[package.extras]
colors = ["colorama (>=0.4.3)"]
pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
plugins = ["setuptools"]
requirements-deprecated-finder = ["pip-api", "pipreqs"]
[[package]]
name = "lazy-object-proxy"
version = "1.9.0"
description = "A fast and thorough lazy object proxy."
optional = false
python-versions = ">=3.7"
files = [
{file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"},
{file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"},
{file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"},
{file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"},
{file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"},
{file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"},
{file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"},
{file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"},
{file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"},
{file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"},
{file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"},
{file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"},
{file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"},
{file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"},
{file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"},
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"},
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"},
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"},
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"},
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"},
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"},
{file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"},
{file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"},
{file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"},
{file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"},
{file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"},
{file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"},
{file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"},
{file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"},
{file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"},
{file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"},
{file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"},
{file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"},
{file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"},
{file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"},
{file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"},
]
[[package]] [[package]]
name = "macholib" name = "macholib"
version = "1.16.3" version = "1.16.3"
@@ -96,6 +199,17 @@ files = [
[package.dependencies] [package.dependencies]
altgraph = ">=0.17" altgraph = ">=0.17"
[[package]]
name = "mccabe"
version = "0.7.0"
description = "McCabe checker, plugin for flake8"
optional = false
python-versions = ">=3.6"
files = [
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
]
[[package]] [[package]]
name = "nodeenv" name = "nodeenv"
version = "1.8.0" version = "1.8.0"
@@ -149,13 +263,13 @@ files = [
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "23.1" version = "23.2"
description = "Core utilities for Python packages" description = "Core utilities for Python packages"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
] ]
[[package]] [[package]]
@@ -234,13 +348,13 @@ files = [
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "3.10.0" version = "3.11.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"},
{file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"},
] ]
[package.extras] [package.extras]
@@ -310,6 +424,32 @@ files = [
{file = "pyinstaller_hooks_contrib-2023.9-py2.py3-none-any.whl", hash = "sha256:f34f4c6807210025c8073ebe665f422a3aa2ac5f4c7ebf4c2a26cc77bebf63b5"}, {file = "pyinstaller_hooks_contrib-2023.9-py2.py3-none-any.whl", hash = "sha256:f34f4c6807210025c8073ebe665f422a3aa2ac5f4c7ebf4c2a26cc77bebf63b5"},
] ]
[[package]]
name = "pylint"
version = "2.17.7"
description = "python code static checker"
optional = false
python-versions = ">=3.7.2"
files = [
{file = "pylint-2.17.7-py3-none-any.whl", hash = "sha256:27a8d4c7ddc8c2f8c18aa0050148f89ffc09838142193fdbe98f172781a3ff87"},
{file = "pylint-2.17.7.tar.gz", hash = "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad"},
]
[package.dependencies]
astroid = ">=2.15.8,<=2.17.0-dev0"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
dill = {version = ">=0.2", markers = "python_version < \"3.11\""}
isort = ">=4.2.5,<6"
mccabe = ">=0.6,<0.8"
platformdirs = ">=2.2.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
tomlkit = ">=0.10.1"
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
[package.extras]
spelling = ["pyenchant (>=3.2,<4.0)"]
testutils = ["gitpython (>3)"]
[[package]] [[package]]
name = "pyside2" name = "pyside2"
version = "5.15.2.1" version = "5.15.2.1"
@@ -465,6 +605,39 @@ files = [
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
] ]
[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "tomlkit"
version = "0.12.1"
description = "Style preserving TOML library"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"},
{file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"},
]
[[package]]
name = "typing-extensions"
version = "4.8.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
]
[[package]] [[package]]
name = "tzdata" name = "tzdata"
version = "2023.3" version = "2023.3"
@@ -496,6 +669,90 @@ platformdirs = ">=3.9.1,<4"
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
[[package]]
name = "wrapt"
version = "1.15.0"
description = "Module for decorators, wrappers and monkey patching."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
files = [
{file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"},
{file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"},
{file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"},
{file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"},
{file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"},
{file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"},
{file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"},
{file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"},
{file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"},
{file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"},
{file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"},
{file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"},
{file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"},
{file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"},
{file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"},
{file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"},
{file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"},
{file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"},
{file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"},
{file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"},
{file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"},
{file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"},
{file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"},
{file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"},
{file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"},
{file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"},
{file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"},
{file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"},
{file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"},
{file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"},
{file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"},
{file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"},
{file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"},
{file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"},
{file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"},
{file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"},
{file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"},
{file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"},
{file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"},
{file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"},
{file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"},
{file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"},
{file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"},
{file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"},
{file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"},
{file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"},
{file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"},
{file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"},
{file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"},
{file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"},
{file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"},
{file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"},
{file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"},
{file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"},
{file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"},
{file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"},
{file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"},
{file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"},
{file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"},
{file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"},
{file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"},
{file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"},
{file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"},
{file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"},
{file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"},
{file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"},
{file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"},
{file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"},
{file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"},
{file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"},
{file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"},
{file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"},
{file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"},
{file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"},
{file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
]
[[package]] [[package]]
name = "zipp" name = "zipp"
version = "3.17.0" version = "3.17.0"
@@ -514,4 +771,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.8,<3.9" python-versions = ">=3.8,<3.9"
content-hash = "2ee72912250a8c96f04624c665fd1f86b222ac6561ae4f20bedb77160a8d4756" content-hash = "ff683c2a3f778cd6ad946d6aa4b1f567514f36026e07fccffdb2cd7e86778e0a"

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "statapp" name = "statapp"
version = "0.4.2" version = "0.5.0"
description = "" description = ""
authors = [ authors = [
"Maxim Slipenko <statapp@maks1ms.addy.io>" "Maxim Slipenko <statapp@maks1ms.addy.io>"
@@ -12,8 +12,11 @@ readme = "README.md"
python = ">=3.8,<3.9" python = ">=3.8,<3.9"
pre-commit = "^3.4.0" pre-commit = "^3.4.0"
pyinstaller = "^6.0.0" pyinstaller = "^6.0.0"
pandas = "^2.0"
pyside2 = "^5.15.2.1" pyside2 = "^5.15.2.1"
pandas = { version = "^2", markers = "python_version < '3.9'" }
pylint = { version = "^2", markers = "python_version < '3.9'" }
# scipy = { version = "^1", markers = "python_version < '3.9'" }
# openpyxl = "^3.1.2"
[build-system] [build-system]

View File

@@ -1,59 +0,0 @@
# -*- mode: python ; coding: utf-8 -*-
import sys
import typing
from pprint import pprint
if typing.TYPE_CHECKING:
from PyInstaller.building.api import COLLECT, EXE, MERGE, PYZ # noqa: F401
from PyInstaller.building.build_main import Analysis # noqa: F401
from PyInstaller.building.datastruct import TOC, Target, Tree # noqa: F401
from PyInstaller.building.osx import BUNDLE # noqa: F401
from PyInstaller.building.splash import Splash # noqa: F401
from PyInstaller.utils.hooks import copy_metadata
datas = [('statapp/ui/images/*', 'ui/images')]
datas += copy_metadata('statapp')
a = Analysis(
['statapp/__main__.py'],
pathex=[],
binaries=[],
datas=datas,
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
)
prev_binaries = set(a.binaries)
if sys.platform in ('linux', 'darwin'):
a.exclude_system_libraries(list_of_exceptions=[]) # glob expression
print('\n\nSTRIPPED SYSTEM LIBS')
pprint(sorted(set(prev_binaries) - set(a.binaries)))
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='statapp',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='statapp/ui/images/logo.ico',
)

View File

@@ -1,4 +1,5 @@
# -*- mode: python ; coding: utf-8 -*- # -*- mode: python ; coding: utf-8 -*-
import argparse
import sys import sys
import typing import typing
from pprint import pprint from pprint import pprint
@@ -12,6 +13,10 @@ if typing.TYPE_CHECKING:
from PyInstaller.utils.hooks import copy_metadata from PyInstaller.utils.hooks import copy_metadata
parser = argparse.ArgumentParser()
parser.add_argument("--one-file", action="store_true")
options = parser.parse_args()
datas = [('statapp/ui/images/*', 'ui/images')] datas = [('statapp/ui/images/*', 'ui/images')]
datas += copy_metadata('statapp') datas += copy_metadata('statapp')
@@ -35,9 +40,46 @@ if sys.platform in ('linux', 'darwin'):
print('\n\nSTRIPPED SYSTEM LIBS') print('\n\nSTRIPPED SYSTEM LIBS')
pprint(sorted(set(prev_binaries) - set(a.binaries))) pprint(sorted(set(prev_binaries) - set(a.binaries)))
LOCALES = ['ru', 'en']
def remove_unused_translation(item):
dest = str(item[0])
if not dest.startswith('PySide2/Qt/translations'):
return True
for l in LOCALES:
if l in dest:
return True
return False
a.datas = list(filter(remove_unused_translation, a.datas))
pyz = PYZ(a.pure) pyz = PYZ(a.pure)
exe = EXE( if options.one_file:
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='statapp',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='statapp/ui/images/logo.ico',
)
else:
exe = EXE(
pyz, pyz,
a.scripts, a.scripts,
[], [],
@@ -54,8 +96,8 @@ exe = EXE(
codesign_identity=None, codesign_identity=None,
entitlements_file=None, entitlements_file=None,
icon='statapp/ui/images/logo.ico', icon='statapp/ui/images/logo.ico',
) )
coll = COLLECT( coll = COLLECT(
exe, exe,
a.binaries, a.binaries,
a.datas, a.datas,
@@ -63,4 +105,4 @@ coll = COLLECT(
upx=True, upx=True,
upx_exclude=[], upx_exclude=[],
name='statapp', name='statapp',
) )

View File

@@ -31,13 +31,13 @@ def main():
translator = QtCore.QTranslator(app) translator = QtCore.QTranslator(app)
locale = QtCore.QLocale.system().name() locale = QtCore.QLocale.system().name()
path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath) path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)
translator.load('qt_%s' % locale, path) translator.load(f'qt_{locale}', path)
translator.load(f'qtbase_{locale}', path)
app.installTranslator(translator) app.installTranslator(translator)
window = MainWindow() window = MainWindow()
window.show() window.show()
return app.exec_() return app.exec_()
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())

View File

@@ -19,12 +19,11 @@
# #
import sys import sys
from PySide2.QtCore import QSize from PySide2.QtGui import QMovie
from PySide2.QtGui import QMovie, QIcon
from PySide2.QtWidgets import QMainWindow from PySide2.QtWidgets import QMainWindow
from statapp.ui.ui_about_window import Ui_AboutWindow from statapp.ui.ui_about_window import Ui_AboutWindow
from statapp.utils import resource_path from statapp.utils import resourcePath, addIcon
if sys.version_info < (3, 8): if sys.version_info < (3, 8):
import importlib_metadata import importlib_metadata
@@ -40,8 +39,8 @@ class AboutWindow(QMainWindow):
self.ui = Ui_AboutWindow() self.ui = Ui_AboutWindow()
self.ui.setupUi(self) self.ui.setupUi(self)
image_path = resource_path('ui/images/sticker.gif') gifPath = resourcePath('ui/images/sticker.gif')
movie = QMovie(image_path) movie = QMovie(gifPath)
self.ui.labelgif.setMovie(movie) self.ui.labelgif.setMovie(movie)
movie.start() movie.start()
self.movie = movie self.movie = movie
@@ -50,6 +49,4 @@ class AboutWindow(QMainWindow):
version = importlib_metadata.version(__package__ or __name__) version = importlib_metadata.version(__package__ or __name__)
self.ui.versionLabel.setText(f"Версия: {version}") self.ui.versionLabel.setText(f"Версия: {version}")
icon = QIcon() addIcon(self)
icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)

View File

@@ -17,6 +17,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from dataclasses import dataclass
import numpy as np import numpy as np
import pandas as pd import pandas as pd
@@ -24,28 +26,69 @@ DIRECT_LINK = 0
INDIRECT_LINK = 1 INDIRECT_LINK = 1
def generate_x_values(mean, std, typeConnection, y): def generateYValues(mean, std, count):
yMean = np.mean(y) return np.random.normal(mean, std, size=(count, 1))
def generateXValues(mean, std, typeConnection, yColumn):
yMean = np.mean(yColumn)
values = [] values = []
for cur_y in y: for y in yColumn:
raz = np.abs(mean - np.random.normal(mean, std)) raz = np.abs(mean - np.random.normal(mean, std))
if typeConnection == INDIRECT_LINK: if typeConnection == INDIRECT_LINK:
raz *= -1 raz *= -1
if cur_y > yMean: if y > yMean:
x = mean + raz x = mean + raz
elif cur_y < yMean: elif y < yMean:
x = mean - raz x = mean - raz
else: else:
x = mean x = mean
values.append(x) values.append(x)
return np.array(values)
res = np.array(values)
return res.reshape(len(res), 1)
def variance_analysis(data): def varianceAnalysis(data):
return np.array([ return np.array([
[np.mean(col), np.std(col), np.min(col), np.max(col)] for col in data.T [np.mean(col), np.std(col), np.min(col), np.max(col)] for col in data.T
]) ])
def correlation_analysis(data): def correlationAnalysis(data):
return pd.DataFrame(data).corr().to_numpy() return pd.DataFrame(data).corr().to_numpy()
@dataclass()
class LinearPolynomResult:
paramsAndImportance: np.ndarray
residualVariance: np.float64
def linearPolynom(inputData) -> LinearPolynomResult:
x = inputData[:, 1:]
y = inputData[:, 0]
data = pd.DataFrame(x)
data.insert(0, 'const', 1)
# ---
result = np.linalg.lstsq(data, y, rcond=None)
# Коэффициенты регрессии
params = result[0]
# Остатки
residues = result[1]
# Степень свободы
dof = len(data) - len(params)
mse = residues / dof
cov = mse * np.diagonal(np.linalg.inv(data.T @ data))
se = np.sqrt(cov)
tStatistics = params / se
# возможно стоит сделать через np.reshape + np.concatenate
out = pd.DataFrame()
out[0] = params
out[1] = tStatistics
return LinearPolynomResult(
out.to_numpy(),
np.float64(mse[0])
)

View File

@@ -21,24 +21,24 @@ from PySide2.QtCore import QSize
from PySide2.QtGui import QIcon from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QDialog, QHeaderView from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import correlation_analysis from statapp.calculations import correlationAnalysis
from statapp.models.correlation_analysis_model import CorrelationAnalysisModel from statapp.models.correlation_analysis_model import CorrelationAnalysisModel
from statapp.ui.ui_correlation_analysis_window import Ui_CorrelationAnalysisWindow from statapp.ui.ui_correlation_analysis_window import Ui_CorrelationAnalysisWindow
from statapp.utils import resource_path from statapp.utils import resourcePath
class СorrelationAnalysisWindow(QDialog): class CorrelationAnalysisWindow(QDialog):
def __init__(self, data): def __init__(self, data):
super().__init__() super().__init__()
self.ui = Ui_CorrelationAnalysisWindow() self.ui = Ui_CorrelationAnalysisWindow()
self.ui.setupUi(self) self.ui.setupUi(self)
res = correlation_analysis(data) res = correlationAnalysis(data)
self.model = CorrelationAnalysisModel(res.round(2)) self.model = CorrelationAnalysisModel(res.round(2))
self.ui.tableView.setModel(self.model) self.ui.tableView.setModel(self.model)
header = self.ui.tableView.horizontalHeader() header = self.ui.tableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch) header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
icon = QIcon() icon = QIcon()
icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off) icon.addFile(resourcePath("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon) self.setWindowIcon(icon)

View File

@@ -17,13 +17,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from PySide2.QtCore import Slot, QSize from PySide2.QtCore import Slot
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QDialog from PySide2.QtWidgets import QDialog
from statapp.ui.ui_generate_factor_window import Ui_GenerateFactorWindow from statapp.ui.ui_generate_factor_window import Ui_GenerateFactorWindow
from statapp.models.combobox_model import ComboBoxModel from statapp.models.combobox_model import ComboBoxModel
from statapp.utils import resource_path from statapp.utils import addIcon
DIRECT_LINK = 0 DIRECT_LINK = 0
INDIRECT_LINK = 1 INDIRECT_LINK = 1
@@ -44,9 +43,7 @@ class GenerateFactorWindow(QDialog):
self.ui.setupUi(self) self.ui.setupUi(self)
self.ui.typeComboBox.setModel(self._typeComboBox) self.ui.typeComboBox.setModel(self._typeComboBox)
icon = QIcon() addIcon(self)
icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)
@Slot() @Slot()
def on_generatePushButton_clicked(self): def on_generatePushButton_clicked(self):

View File

@@ -17,12 +17,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from PySide2.QtCore import Slot, QSize from PySide2.QtCore import Slot
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QDialog from PySide2.QtWidgets import QDialog
from statapp.ui.ui_generate_window import Ui_GenerateWindow from statapp.ui.ui_generate_window import Ui_GenerateWindow
from statapp.utils import resource_path from statapp.utils import addIcon
class GenerateWindow(QDialog): class GenerateWindow(QDialog):
@@ -34,9 +33,7 @@ class GenerateWindow(QDialog):
self.ui = Ui_GenerateWindow() self.ui = Ui_GenerateWindow()
self.ui.setupUi(self) self.ui.setupUi(self)
icon = QIcon() addIcon(self)
icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)
@Slot() @Slot()

View File

@@ -0,0 +1,42 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import linearPolynom
from statapp.models.linear_polynom_model import LinearPolynomModel
from statapp.ui.ui_linear_polynom_window import Ui_LinearPolynomWindow
from statapp.utils import addIcon
class LinearPolynomWindow(QDialog):
def __init__(self, data):
super().__init__()
self.ui = Ui_LinearPolynomWindow()
self.ui.setupUi(self)
addIcon(self)
result = linearPolynom(data)
self.model = LinearPolynomModel(result.paramsAndImportance.round(2))
self.ui.tableView.setModel(self.model)
header = self.ui.tableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.ui.residualVarianceValueLabel.setText(str(result.residualVariance))

View File

@@ -18,20 +18,20 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import numpy as np import numpy as np
from PySide2.QtCore import Slot, QSize from PySide2.QtCore import Slot
from PySide2.QtGui import QIcon from PySide2.QtWidgets import QMainWindow, QMessageBox
from PySide2.QtWidgets import QMainWindow, QMessageBox, QAction
from statapp.calculations import generate_x_values from statapp.calculations import generateXValues, generateYValues
from statapp.generate_factor_window import GenerateFactorWindow from statapp.generate_factor_window import GenerateFactorWindow
from statapp.linear_polynom_window import LinearPolynomWindow
from statapp.models.input_values_model import InputValuesModel from statapp.models.input_values_model import InputValuesModel
from statapp.generate_window import GenerateWindow from statapp.generate_window import GenerateWindow
from statapp.about_window import AboutWindow from statapp.about_window import AboutWindow
from statapp.models.fileslc_model import FileSLCModel from statapp.models.fileslc_model import FileSLCModel
from statapp.ui.ui_main_window import Ui_MainWindow from statapp.ui.ui_main_window import Ui_MainWindow
from statapp.utils import resource_path, buildMessageBox from statapp.utils import buildMessageBox, addIcon
from statapp.variance_analysis import VarianceAnalysisWindow from statapp.variance_analysis import VarianceAnalysisWindow
from statapp.correlation_analysis import СorrelationAnalysisWindow from statapp.correlation_analysis import CorrelationAnalysisWindow
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
@@ -41,27 +41,63 @@ class MainWindow(QMainWindow):
self.ui = Ui_MainWindow() self.ui = Ui_MainWindow()
self.ui.setupUi(self) self.ui.setupUi(self)
icon = QIcon() addIcon(self)
icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)
self.ui.generateXaction.setEnabled(False) self.ui.generateXaction.setEnabled(False)
self.ui.varianceAnalysisAction.setEnabled(False) self.ui.varianceAnalysisAction.setEnabled(False)
self.ui.correlationAnalisisAction.setEnabled(False) self.ui.correlationAnalisisAction.setEnabled(False)
self.mainActions = [
self.ui.varianceAnalysisAction,
self.ui.correlationAnalisisAction,
self.ui.linearPolynomAction,
]
self.aboutWindow = None
self.isDataChanged = False self.isDataChanged = False
self.model = InputValuesModel() self.model = InputValuesModel()
self.fileModel = FileSLCModel() self.fileModel = FileSLCModel()
self.ui.tableView.setModel(self.model) self.ui.tableView.setModel(self.model)
self.model.layoutChanged.connect(self.updateActionsEnabled)
self.updateActionsEnabled()
#
# Для быстрой отладки
# n = 10
# y = generateYValues(100, 5, n)
# x1 = generateXValues(20, 2, 0, y)
# x2 = generateXValues(10, 1, 0, y)
# self.model.updateAllData(np.concatenate([y, x1, x2], axis=1))
def updateActionsEnabled(self):
data = self.model.getData()
# есть только отклик
if data.shape[1] == 1:
self.ui.generateXaction.setEnabled(True)
self.setEnabledMainActions(False)
# есть отклик и фактор(ы)
elif data.shape[1] > 1:
self.ui.generateXaction.setEnabled(True)
self.setEnabledMainActions(True)
else:
self.ui.generateXaction.setEnabled(False)
self.setEnabledMainActions(False)
def setEnabledMainActions(self, enabled):
for action in self.mainActions:
action.setEnabled(enabled)
@Slot() @Slot()
def on_openfileaction_triggered(self): def on_openfileaction_triggered(self):
current_data = self.model.getData() currentData = self.model.getData()
data = np.array([]) data = np.array([])
if current_data.size > 1: if currentData.size > 1:
file = '' file = ''
if self.fileModel.file_name: if self.fileModel.fileName:
file = '\nФайл сохранения: ' + self.fileModel.file_name file = '\nФайл сохранения: ' + self.fileModel.fileName
msgBox = buildMessageBox \ msgBox = buildMessageBox \
('Сохранение данных', ('Сохранение данных',
@@ -86,18 +122,6 @@ class MainWindow(QMainWindow):
self.model.updateAllData(data) self.model.updateAllData(data)
self.isDataChanged = False self.isDataChanged = False
if data.shape[1] == 1:
self.ui.generateXaction.setEnabled(True)
self.ui.varianceAnalysisAction.setEnabled(False)
self.ui.correlationAnalisisAction.setEnabled(False)
elif data.shape[1] > 1:
self.ui.generateXaction.setEnabled(True)
self.ui.varianceAnalysisAction.setEnabled(True)
self.ui.correlationAnalisisAction.setEnabled(True)
else:
self.ui.generateXaction.setEnabled(False)
self.ui.varianceAnalysisAction.setEnabled(False)
self.ui.correlationAnalisisAction.setEnabled(False)
@Slot() @Slot()
def on_savefileaction_triggered(self): def on_savefileaction_triggered(self):
@@ -113,10 +137,9 @@ class MainWindow(QMainWindow):
gw = GenerateWindow() gw = GenerateWindow()
if gw.exec(): if gw.exec():
y = np.random.normal(gw.mat, gw.deviation, size=(gw.count, 1)) y = generateYValues(gw.mat, gw.deviation, gw.count)
self.model.updateAllData(y.round(2)) self.model.updateAllData(y.round(2))
self.isDataChanged = True self.isDataChanged = True
self.ui.generateXaction.setEnabled(True)
@Slot() @Slot()
def on_generateXaction_triggered(self): def on_generateXaction_triggered(self):
@@ -125,20 +148,15 @@ class MainWindow(QMainWindow):
if gfw.exec(): if gfw.exec():
data = self.model.getData() data = self.model.getData()
y = self.model.getY() y = self.model.getY()
x_arr = generate_x_values(gfw.mat, gfw.deviation, gfw.typeConnection, y) xValues = generateXValues(gfw.mat, gfw.deviation, gfw.typeConnection, y)
x_arr = x_arr.reshape(len(x_arr), 1).round(2) data = np.concatenate((data, xValues.round(2)), axis=1)
# dd = dd.reshape(len(dd), 1)
data = np.concatenate((data, x_arr), axis=1)
self.model.updateAllData(data) self.model.updateAllData(data)
self.ui.varianceAnalysisAction.setEnabled(True)
self.ui.correlationAnalisisAction.setEnabled(True)
self.isDataChanged = True self.isDataChanged = True
@Slot() @Slot()
def on_aboutmenuaction_triggered(self): def on_aboutmenuaction_triggered(self):
global about_window self.aboutWindow = AboutWindow()
about_window = AboutWindow() self.aboutWindow.show()
about_window.show()
@Slot() @Slot()
def on_varianceAnalysisAction_triggered(self): def on_varianceAnalysisAction_triggered(self):
@@ -147,14 +165,19 @@ class MainWindow(QMainWindow):
@Slot() @Slot()
def on_correlationAnalisisAction_triggered(self): def on_correlationAnalisisAction_triggered(self):
dw = СorrelationAnalysisWindow(self.model.getData()) dw = CorrelationAnalysisWindow(self.model.getData())
dw.exec()
@Slot()
def on_linearPolynomAction_triggered(self):
dw = LinearPolynomWindow(self.model.getData())
dw.exec() dw.exec()
def closeEvent(self, event): def closeEvent(self, event):
if self.isDataChanged: if self.isDataChanged:
file = '' file = ''
if self.fileModel.file_name: if self.fileModel.fileName:
file = '\nФайл сохранения: ' + self.fileModel.file_name file = '\nФайл сохранения: ' + self.fileModel.fileName
msgBox = buildMessageBox \ msgBox = buildMessageBox \
('Завершение работы', ('Завершение работы',

View File

@@ -20,7 +20,7 @@
from PySide2.QtCore import QModelIndex, Qt from PySide2.QtCore import QModelIndex, Qt
from statapp.models.ro_table_model import ROTableModel from statapp.models.ro_table_model import ROTableModel
from statapp.models.utils import yx_header from statapp.models.utils import yxHeader
class CorrelationAnalysisModel(ROTableModel): class CorrelationAnalysisModel(ROTableModel):
@@ -28,15 +28,12 @@ class CorrelationAnalysisModel(ROTableModel):
super().__init__(data) super().__init__(data)
def getHorizontalHeader(self): def getHorizontalHeader(self):
return yx_header(self.columnCount(QModelIndex())) return yxHeader(self.columnCount(QModelIndex()))
def getVerticalHeader(self): def getVerticalHeader(self):
return yx_header(self.rowCount(QModelIndex())) return yxHeader(self.rowCount(QModelIndex()))
def data(self, index, role): def data(self, index, role):
if role == Qt.DisplayRole: if role == Qt.DisplayRole and index.column() <= index.row():
if (index.column() <= index.row()): return super().data(index, role)
return float(self._data[index.row(), index.column()])
else:
None
return None return None

View File

@@ -43,7 +43,7 @@ class EditableTableModel(ROTableModel):
return False return False
def data(self, index, role): def data(self, index, role):
if role == Qt.DisplayRole or role == Qt.EditRole: if role in (Qt.DisplayRole, Qt.EditRole):
return float(self._data[index.row(), index.column()]) return super().data(index, Qt.DisplayRole)
return None return None

View File

@@ -24,30 +24,35 @@ from PySide2.QtWidgets import QFileDialog, QMessageBox
class FileSLCModel: class FileSLCModel:
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.file_name = None self.fileName = None
def saveFile(self, data): def saveFile(self, data):
if not self.file_name: if not self.fileName:
self.file_name, _ = QFileDialog.getSaveFileName(None, "Сохранить файл", "", "Text Files (*.txt);;CSV Files (*.csv)") self.fileName, _ = QFileDialog.getSaveFileName(
if self.file_name: None, "Сохранить файл", "", "Text Files (*.txt);;CSV Files (*.csv)"
np.savetxt(self.file_name, data, delimiter=",") )
if self.fileName:
np.savetxt(self.fileName, data, delimiter=",")
return True return True
return False return False
def loadFile(self): def loadFile(self):
self.file_name, _ = QFileDialog.getOpenFileName(None, "Загрузить файл", "", "Files (*.txt *.csv)") self.fileName, _ = QFileDialog.getOpenFileName(
if self.file_name: None, "Загрузить файл", "", "Files (*.txt *.csv)"
)
if self.fileName:
try: try:
content = np.genfromtxt(self.file_name, delimiter=',', invalid_raise=True, ndmin=2) content = np.genfromtxt(self.fileName, delimiter=',', invalid_raise=True, ndmin=2)
except ValueError as e: except ValueError:
QMessageBox.warning \ QMessageBox.warning \
(None, (None,
'Ошибка', 'Ошибка',
"Ошибка чтения файла!\nФайл нельзя открыть или файл неверного формата") "Ошибка чтения файла!\nФайл нельзя открыть или файл неверного формата")
self.file_name = None self.fileName = None
return None return None
return content return content
return None
def closeFile(self): def closeFile(self):
self.file_name = None self.fileName = None
pass

View File

@@ -18,10 +18,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import numpy as np import numpy as np
from PySide2.QtCore import Qt, QModelIndex from PySide2.QtCore import QModelIndex
from statapp.models.editable_table_model import EditableTableModel from statapp.models.editable_table_model import EditableTableModel
from statapp.models.utils import yx_header from statapp.models.utils import yxHeader
class InputValuesModel(EditableTableModel): class InputValuesModel(EditableTableModel):
@@ -29,7 +29,7 @@ class InputValuesModel(EditableTableModel):
super().__init__(data) super().__init__(data)
def getHorizontalHeader(self): def getHorizontalHeader(self):
return yx_header(self.columnCount(QModelIndex())) return yxHeader(self.columnCount(QModelIndex()))
def getY(self): def getY(self):
return self._data[:, 0] return self._data[:, 0]

View File

@@ -0,0 +1,31 @@
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from PySide2.QtCore import QModelIndex
from statapp.models.ro_table_model import ROTableModel
class LinearPolynomModel(ROTableModel):
def getHorizontalHeader(self):
return ['Коэффициент регрессии', 'Коэффициент значимости']
def getVerticalHeader(self):
count = (self.rowCount(QModelIndex()))
return ['Свободный член'] + [f'X{i}' for i in range(1, count)]

View File

@@ -17,12 +17,11 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import PySide2
import numpy as np import numpy as np
from PySide2 import QtCore from PySide2 import QtCore
from PySide2.QtCore import Qt from PySide2.QtCore import Qt
from statapp.utils import safe_list_get from statapp.utils import safeListGet
class ROTableModel(QtCore.QAbstractTableModel): class ROTableModel(QtCore.QAbstractTableModel):
@@ -55,7 +54,7 @@ class ROTableModel(QtCore.QAbstractTableModel):
def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...): def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...):
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
return safe_list_get(self._headers[orientation](), section, None) return safeListGet(self._headers[orientation](), section, None)
return None return None

View File

@@ -17,5 +17,5 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
def yx_header(count): def yxHeader(count):
return ['Y'] + [f'X{i}' for i in range(1, count)] return ['Y'] + [f'X{i}' for i in range(1, count)]

View File

@@ -20,7 +20,7 @@
from PySide2.QtCore import QModelIndex from PySide2.QtCore import QModelIndex
from statapp.models.ro_table_model import ROTableModel from statapp.models.ro_table_model import ROTableModel
from statapp.models.utils import yx_header from statapp.models.utils import yxHeader
class VarianceAnalysisModel(ROTableModel): class VarianceAnalysisModel(ROTableModel):
@@ -31,4 +31,4 @@ class VarianceAnalysisModel(ROTableModel):
return ['Мат. ожидание', 'Среднекв. отклонение', 'Минимум', 'Максимум'] return ['Мат. ожидание', 'Среднекв. отклонение', 'Минимум', 'Максимум']
def getVerticalHeader(self): def getVerticalHeader(self):
return yx_header(self.rowCount(QModelIndex())) return yxHeader(self.rowCount(QModelIndex()))

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LinearPolynomWindow</class>
<widget class="QDialog" name="LinearPolynomWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>630</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Линейный полином</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTableView" name="tableView"/>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_3">
<property name="topMargin">
<number>10</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="residualVarianceLabel">
<property name="text">
<string>Остаточная дисперсия:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="residualVarianceValueLabel">
<property name="text">
<string>undefined</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -40,7 +40,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>800</width>
<height>21</height> <height>27</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="filemenu"> <widget class="QMenu" name="filemenu">
@@ -69,6 +69,7 @@
<property name="title"> <property name="title">
<string>Моделирование</string> <string>Моделирование</string>
</property> </property>
<addaction name="linearPolynomAction"/>
</widget> </widget>
<widget class="QMenu" name="helpmenu"> <widget class="QMenu" name="helpmenu">
<property name="title"> <property name="title">
@@ -123,6 +124,11 @@
<string>Корреляционный анализ</string> <string>Корреляционный анализ</string>
</property> </property>
</action> </action>
<action name="linearPolynomAction">
<property name="text">
<string>Линейный полином</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

79
statapp/ui/ui_linear_polynom_window.py generated Normal file
View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2023 Maxim Slipenko, Eugene Lazurenko.
#
# This file is part of Statapp
# (see https://github.com/shizand/statapp).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
## Form generated from reading UI file 'linear_polynom_window.ui'
##
## Created by: Qt User Interface Compiler version 5.15.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
class Ui_LinearPolynomWindow(object):
def setupUi(self, LinearPolynomWindow):
if not LinearPolynomWindow.objectName():
LinearPolynomWindow.setObjectName(u"LinearPolynomWindow")
LinearPolynomWindow.resize(630, 400)
self.gridLayout_2 = QGridLayout(LinearPolynomWindow)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.tableView = QTableView(LinearPolynomWindow)
self.tableView.setObjectName(u"tableView")
self.gridLayout.addWidget(self.tableView, 0, 0, 1, 1)
self.gridLayout_3 = QGridLayout()
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.gridLayout_3.setContentsMargins(-1, 10, -1, -1)
self.residualVarianceLabel = QLabel(LinearPolynomWindow)
self.residualVarianceLabel.setObjectName(u"residualVarianceLabel")
self.gridLayout_3.addWidget(self.residualVarianceLabel, 0, 0, 1, 1)
self.residualVarianceValueLabel = QLabel(LinearPolynomWindow)
self.residualVarianceValueLabel.setObjectName(u"residualVarianceValueLabel")
self.gridLayout_3.addWidget(self.residualVarianceValueLabel, 0, 1, 1, 1)
self.gridLayout.addLayout(self.gridLayout_3, 1, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
self.retranslateUi(LinearPolynomWindow)
QMetaObject.connectSlotsByName(LinearPolynomWindow)
# setupUi
def retranslateUi(self, LinearPolynomWindow):
LinearPolynomWindow.setWindowTitle(QCoreApplication.translate("LinearPolynomWindow", u"\u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u043d\u043e\u043c", None))
self.residualVarianceLabel.setText(QCoreApplication.translate("LinearPolynomWindow", u"\u041e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430\u044f \u0434\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u044f:", None))
self.residualVarianceValueLabel.setText(QCoreApplication.translate("LinearPolynomWindow", u"undefined", None))
# retranslateUi

View File

@@ -54,6 +54,8 @@ class Ui_MainWindow(object):
self.varianceAnalysisAction.setObjectName(u"varianceAnalysisAction") self.varianceAnalysisAction.setObjectName(u"varianceAnalysisAction")
self.correlationAnalisisAction = QAction(MainWindow) self.correlationAnalisisAction = QAction(MainWindow)
self.correlationAnalisisAction.setObjectName(u"correlationAnalisisAction") self.correlationAnalisisAction.setObjectName(u"correlationAnalisisAction")
self.linearPolynomAction = QAction(MainWindow)
self.linearPolynomAction.setObjectName(u"linearPolynomAction")
self.centralwidget = QWidget(MainWindow) self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget") self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout = QGridLayout(self.centralwidget)
@@ -73,7 +75,7 @@ class Ui_MainWindow(object):
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow) self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar") self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 800, 21)) self.menubar.setGeometry(QRect(0, 0, 800, 27))
self.filemenu = QMenu(self.menubar) self.filemenu = QMenu(self.menubar)
self.filemenu.setObjectName(u"filemenu") self.filemenu.setObjectName(u"filemenu")
self.generatemenu = QMenu(self.menubar) self.generatemenu = QMenu(self.menubar)
@@ -101,6 +103,7 @@ class Ui_MainWindow(object):
self.generatemenu.addAction(self.generateXaction) self.generatemenu.addAction(self.generateXaction)
self.analyzemenu.addAction(self.varianceAnalysisAction) self.analyzemenu.addAction(self.varianceAnalysisAction)
self.analyzemenu.addAction(self.correlationAnalisisAction) self.analyzemenu.addAction(self.correlationAnalisisAction)
self.modelmenu.addAction(self.linearPolynomAction)
self.helpmenu.addAction(self.aboutmenuaction) self.helpmenu.addAction(self.aboutmenuaction)
self.retranslateUi(MainWindow) self.retranslateUi(MainWindow)
@@ -118,6 +121,7 @@ class Ui_MainWindow(object):
self.closefileaction.setText(QCoreApplication.translate("MainWindow", u"\u0417\u0430\u043a\u0440\u044b\u0442\u044c", None)) self.closefileaction.setText(QCoreApplication.translate("MainWindow", u"\u0417\u0430\u043a\u0440\u044b\u0442\u044c", None))
self.varianceAnalysisAction.setText(QCoreApplication.translate("MainWindow", u"\u0414\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None)) self.varianceAnalysisAction.setText(QCoreApplication.translate("MainWindow", u"\u0414\u0438\u0441\u043f\u0435\u0440\u0441\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None))
self.correlationAnalisisAction.setText(QCoreApplication.translate("MainWindow", u"\u041a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None)) self.correlationAnalisisAction.setText(QCoreApplication.translate("MainWindow", u"\u041a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437", None))
self.linearPolynomAction.setText(QCoreApplication.translate("MainWindow", u"\u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u043d\u043e\u043c", None))
self.label.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0422\u0410\u0422\u0418\u0421\u0422\u0418\u0427\u0415\u0421\u041a\u0418\u0415 \u0414\u0410\u041d\u041d\u042b\u0415", None)) self.label.setText(QCoreApplication.translate("MainWindow", u"\u0421\u0422\u0410\u0422\u0418\u0421\u0422\u0418\u0427\u0415\u0421\u041a\u0418\u0415 \u0414\u0410\u041d\u041d\u042b\u0415", None))
self.filemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0424\u0430\u0439\u043b", None)) self.filemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0424\u0430\u0439\u043b", None))
self.generatemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439", None)) self.generatemenu.setTitle(QCoreApplication.translate("MainWindow", u"\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439", None))

View File

@@ -20,21 +20,30 @@
import os import os
import sys import sys
from PySide2.QtCore import QSize
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QMessageBox from PySide2.QtWidgets import QMessageBox
def resource_path(relative): def resourcePath(relative):
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
bundle_dir = sys._MEIPASS # pylint: disable=protected-access
bundleDir = sys._MEIPASS
else: else:
# we are running in a normal Python environment # we are running in a normal Python environment
bundle_dir = os.path.dirname(os.path.abspath(__file__)) bundleDir = os.path.dirname(os.path.abspath(__file__))
return os.path.join(bundle_dir, relative) return os.path.join(bundleDir, relative)
def safe_list_get(l, idx, default): def addIcon(windowOrDialog):
icon = QIcon()
icon.addFile(resourcePath("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off)
windowOrDialog.setWindowIcon(icon)
def safeListGet(lst, idx, default):
try: try:
return l[idx] return lst[idx]
except IndexError: except IndexError:
return default return default

View File

@@ -17,14 +17,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from PySide2.QtCore import QSize
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QDialog, QHeaderView from PySide2.QtWidgets import QDialog, QHeaderView
from statapp.calculations import variance_analysis from statapp.calculations import varianceAnalysis
from statapp.models.variance_analysis_model import VarianceAnalysisModel from statapp.models.variance_analysis_model import VarianceAnalysisModel
from statapp.ui.ui_variance_analysis_window import Ui_VarianceAnalysisWindow from statapp.ui.ui_variance_analysis_window import Ui_VarianceAnalysisWindow
from statapp.utils import resource_path from statapp.utils import addIcon
class VarianceAnalysisWindow(QDialog): class VarianceAnalysisWindow(QDialog):
@@ -33,12 +31,10 @@ class VarianceAnalysisWindow(QDialog):
self.ui = Ui_VarianceAnalysisWindow() self.ui = Ui_VarianceAnalysisWindow()
self.ui.setupUi(self) self.ui.setupUi(self)
res = variance_analysis(data) res = varianceAnalysis(data)
self.model = VarianceAnalysisModel(res.round(2)) self.model = VarianceAnalysisModel(res.round(2))
self.ui.tableView.setModel(self.model) self.ui.tableView.setModel(self.model)
header = self.ui.tableView.horizontalHeader() header = self.ui.tableView.horizontalHeader()
header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch) header.setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
icon = QIcon() addIcon(self)
icon.addFile(resource_path("ui/images/logo.ico"), QSize(), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)