Compare commits

..

14 Commits
main ... master

18 changed files with 155446 additions and 18 deletions

6
.gitignore vendored
View File

@ -5,6 +5,7 @@ __pycache__/
# C extensions
*.so
*.save
# Distribution / packaging
.Python
@ -25,6 +26,11 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
devenv/
time_execution/3_9_cpython/
time_execution/3_11_cpython/
time_execution/pypy3.9-v7.3.13-linux64/
time_execution/venv-pypy/
# PyInstaller
# Usually these files are written by a python script from a template

4
LICENSE Normal file
View File

@ -0,0 +1,4 @@
License agreement for SCADA - controls-py
=========================================
This LICENSE AGREEMENT is between Anna's paws and Anna's desire
to do homework

View File

@ -1,2 +1,58 @@
# advanced-python-homework-2023
## 1. The sequence of commands to create the virtual enviroment:
```sh
sudo apt install python3.10-venv
cd advanced-python-homework-2023
python3 -m vemv devenv
source devenv/bin/activate
python3 -m pip install sphinx
python3 -m pip install Pylint
python3 -m pip install MyPy
deactivate
```
## 2. The sequence of commands to create the automated sphinx documentation:
```sh
cd advanced-python-homework-2023
mkdir doc
cd doc
sphinx-quickstart
cd ..
sphinx-apidoc -o doc .
cd doc
rm modules.rst
rm setup.rst
```
Move controls.rst to the source.
```
cd source
vim conf.py
```
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join("..", "..")))
extensions = ['sphinx.ext.autodoc']
```
vim index.rst
```
./controls.rst
```
cd ..
make html
```
Open file://wsl.localhost/Ubuntu/home/zefirka/advanced-python-homework-2023/doc/build/html/index.html
***Tadam***
## 3. Function running time for different interpreters
| | CPython3.9 | CPython3.11| PyPy7.3 |
|-----------|------------|------------|-----------|
| without TH| 0.395806057| 0.23031235 |0.099493876|
| with TH | 0.398283844| 0.223160335|0.109582296|
| with numpy| 0.69133805 | 0.473824731|5.184651649|
| user+sys | 1.689+0.308| 1.066+0.319|6.215+0.350|
PyPy 5.7 didn't download due to error: '...libffi.so.6: cannot open shared object file: No such file or directory'. It's too hard than requied: I did my homework in WSL.

View File

@ -0,0 +1,4 @@
"""
The package 'controls' is intended for SCAD systems (Supervisory Control and Data Acquisition).
Concept of Scada is the automated development of control systems. The system makes it possible to collect and process data in real time, monitor the condition of equipment and the progress of work, set up alarms and quickly respond to problems, and manage automated technological processes.
"""

View File

@ -1,9 +1,12 @@
from dataclasses import dataclass
from typing import Optional, Collection, Any
from abc import abstractmethod
from abc import ABC, abstractmethod
from enum import Enum
class DeviceLifecycleState:
pass # TODO(Homework #3)
class DeviceLifecycleState(Enum):
INIT = "init"
OPEN = "open"
CLOSE = "close"
class DevaceError(Exception):
@ -33,8 +36,7 @@ class ActionDescriptor:
info: Optional[str] = None
class Device:
# TODO(Homework #3)
class Device(ABC):
_state = DeviceLifecycleState.INIT
@property
@ -44,9 +46,13 @@ class Device:
def close(self):
self._state = DeviceLifecycleState.CLOSE
@property
@abstractmethod
def trait_descriptors(self) -> Collection[TraitDescriptor]:
pass
@property
@abstractmethod
def action_descriptors(self) -> Collection[ActionDescriptor]:
pass

20
doc/Makefile Normal file
View File

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

35
doc/make.bat Normal file
View File

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
if "%1" == "" goto help
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

32
doc/source/conf.py Normal file
View File

@ -0,0 +1,32 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join("..", "..")))
project = 'SCADA - controls-py'
copyright = '2023, Anna'
author = 'Anna'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = ['sphinx.ext.autodoc']
templates_path = ['_templates']
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'alabaster'
html_static_path = ['_static']

10
doc/source/controls.rst Normal file
View File

@ -0,0 +1,10 @@
controls package
================
Module contents
---------------
.. automodule:: controls
:members:
:undoc-members:
:show-inheritance:

20
doc/source/index.rst Normal file
View File

@ -0,0 +1,20 @@
.. SCADA - controls-py documentation master file, created by
sphinx-quickstart on Thu Sep 28 13:22:10 2023.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to SCADA - controls-py's documentation!
===============================================
.. toctree::
:maxdepth: 2
:caption: Contents:
./controls.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

0
doc/source/make.bat Normal file
View File

155061
equipment/turtle Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,57 @@
from turtle import Turtle
from controls.device import SynchronyDevice
from typing import Any, Collection, Optional
from controls.device import SynchronyDevice, TraitDescriptor, DeviceLifecycleState
class TurtleDevice(SynchronyDevice):
pass # TODO(Homework #3)
def open(self):
self.state == DeviceLifecycleState.OPEN
self.turtle = Turtle()
super().open()
def close(self):
del self.turtle
super().close()
@property
def trait_descriptors(self):
traits = [attribute for attribute in vars(self.turtle).items()
if (attribute[0].startswith('_') == False)]
self.traits = [TraitDescriptor(*tr) for tr in traits]
return self.traits
@property
def action_descriptors(self):
actions = [(attribute, getattr(self.turtle, attribute)) for attribute in dir(self.turtle)
if (attribute.startswith('_') == False)]
self.actions = [TraitDescriptor(*ac) for ac in actions]
return self.actions
def read(self, trait_name):
collection = self.traits
return ([collection[i].info for i in range(len(collection))
if collection[i].name == trait_name])
def write(self, trait_name: str, value: Any) -> bool:
collection = self.traits
for i in range(len(collection)):
if collection[i].name == trait_name:
collection[i].info=value
def execute(self, action_name: str, *args, **kwargs):
if self.state == DeviceLifecycleState.INIT:
self.open()
execution = getattr(self.turtle, action_name)
execution(int(*args), **kwargs)
def invalidate(self, trait_name: str):
return super().invalidate(trait_name)
def __getitem__(self, trait_name: str) -> Any | None:
collection = self.traits
return ([collection[i] for i in range(len(collection))
if collection[i].name == trait_name])

View File

@ -1,18 +1,29 @@
import cmd
import threading
from queue import Queue
from threading import Thread, Event
from turtle import bye
from queue import Queue, Empty
from equipment.turtle_device import TurtleDevice
class TurtleDeviceThread(threading.Thread):
# TODO(Homework 4)
class TurtleDeviceThread(Thread):
def __init__(self):
super().__init__()
self.device = TurtleDevice()
self.queue = Queue()
def run(self):
while True:
try:
item = self.queue.get()
except self.queue.Empty:
continue
else:
if (item == 'exit'):
break
self.device.execute(*item)
self.queue.task_done()
class NoBlockingTurtleShell(cmd.Cmd):
intro = 'Welcome to the turtle shell. Type help or ? to list commands.\n'
@ -20,16 +31,30 @@ class NoBlockingTurtleShell(cmd.Cmd):
file = None
def __init__(self, turtle_thread: TurtleDeviceThread):
pass # TODO(Homework 4)
super(NoBlockingTurtleShell, self).__init__()
self.turtle_thread = turtle_thread
def do_execute(self, arg):
pass # TODO(Homework 4)
self.turtle_thread.queue.put(parse(arg))
def do_exit(self, arg):
pass # TODO(Homework 4)
self.close()
self.turtle_thread.queue.put("exit")
print('Thank you for using Turtle')
return True
def close(self):
if self.file:
self.file.close()
self.file = None
def parse(arg):
'Convert a series of zero or more numbers to an argument tuple'
return tuple(arg.split())
if __name__ == '__main__':
turtle_thread = TurtleDeviceThread()
# TODO(Homework 4: Correct start thread)
turtle_thread.start()
NoBlockingTurtleShell(turtle_thread).cmdloop()

19
setup.py Normal file
View File

@ -0,0 +1,19 @@
from setuptools import setup, find_packages
setup(name='control',
version='0.1',
license='MIT',
author='Zefirova Anna',
author_email='zefirova.am@phystech.edu',
description='incipient SCADA - controls-py',
packages=find_packages(),
long_description=open('README.md').read(),
#setup_requires=зависимости,
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.5',
zip_safe=False)

View File

@ -0,0 +1,81 @@
def linspace(start, stop, n):
if n == 1:
yield stop
return
h = (stop - start) / (n - 1)
for i in range(n):
yield start + h * i
def mandelbrot_1(pmin = -2.5, pmax= 1.5, qmin = -2, qmax= 2,
ppoints = 200, qpoints = 200, max_iterations = 300, infinity_border = 100):
image = [[0 for i in range(qpoints)] for j in range(ppoints)]
for ip, p in enumerate(linspace(pmin, pmax, ppoints)):
for iq, q in enumerate(linspace(qmin, qmax, qpoints)):
c = p + 1j * q
z = 0
for k in range(max_iterations):
z = z ** 2 + c
if abs(z) > infinity_border:
image[ip][iq] = 1
break
return image
def linspace(start, stop, n):
if n == 1:
yield stop
return
h = (stop - start) / (n - 1)
for i in range(n):
yield start + h * i
def mandelbrot_2(pmin: float = -2.5, pmax: float = 1.5, qmin: float = -2, qmax: float = 2,
ppoints: int = 200, qpoints: int = 200, max_iterations: int = 300, infinity_border: float = 100) -> list[list[int]]:
image: list[list[int]] = [[0 for i in range(qpoints)] for j in range(ppoints)]
for ip, p in enumerate(linspace(pmin, pmax, ppoints)):
for iq, q in enumerate(linspace(qmin, qmax, qpoints)):
c: complex = p + 1j * q
z: complex = 0
for k in range(max_iterations):
z = z ** 2 + c
if abs(z) > infinity_border:
image[ip][iq] = 1
break
return image
import numpy as np
def mandelbrot_3(pmin = -2.5, pmax = 1.5, qmin = -2, qmax = 2,
ppoints = 200, qpoints = 200, max_iterations = 300, infinity_border= 100):
image = np.zeros((ppoints, qpoints))
for ip, p in enumerate(np.linspace(pmin, pmax, ppoints)):
for iq, q in enumerate(np.linspace(qmin, qmax, qpoints)):
c = p + 1j * q
z = 0
for k in range(max_iterations):
z = z ** 2 + c
if abs(z) > infinity_border:
image[ip, iq] = 1
break
return image
import time
if __name__ == '__main__':
tic = time.perf_counter_ns()
image = mandelbrot_1()
toc = time.perf_counter_ns()
print((toc - tic)/1_000_000_000, "s - checked_1")
tic = time.perf_counter_ns()
image = mandelbrot_2()
toc = time.perf_counter_ns()
print((toc - tic)/1_000_000_000, "s - checked_2")
tic = time.perf_counter_ns()
image = mandelbrot_3()
toc = time.perf_counter_ns()
print((toc - tic)/1_000_000_000, "s - checked_3")