├── pyspectator ├── __init__.py ├── convert.py ├── monitoring.py ├── temperature_reader.py ├── collection.py ├── network.py ├── computer.py ├── memory.py └── processor.py ├── pytest.ini ├── setup.cfg ├── requirements ├── default.txt ├── linux.txt └── windows.txt ├── docs ├── _static │ └── favicon.ico ├── modules │ ├── network.rst │ ├── computer.rst │ ├── convert.rst │ ├── collection.rst │ ├── memory.rst │ └── processor.rst ├── index.rst ├── Makefile ├── make.bat └── conf.py ├── test ├── __init__.py ├── test_convert.py └── test_collection.py ├── MANIFEST.in ├── .gitignore ├── .github └── workflows │ └── python-publish.yml ├── LICENSE ├── README.rst ├── console.py ├── setup.py └── .pylintrc /pyspectator/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | testpaths = test 3 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.rst -------------------------------------------------------------------------------- /requirements/default.txt: -------------------------------------------------------------------------------- 1 | psutil>=2.1.1 2 | netifaces>=0.10.4 3 | pyvalid>=1.0 4 | enum34>=1.1 -------------------------------------------------------------------------------- /requirements/linux.txt: -------------------------------------------------------------------------------- 1 | psutil>=2.1.1 2 | netifaces>=0.10.4 3 | pyvalid>=1.0 4 | enum34>=1.1 5 | distro>=1.5 -------------------------------------------------------------------------------- /docs/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/it-geeks-club/pyspectator/HEAD/docs/_static/favicon.ico -------------------------------------------------------------------------------- /requirements/windows.txt: -------------------------------------------------------------------------------- 1 | psutil>=2.1.1 2 | netifaces>=0.10.4 3 | pyvalid>=1.0 4 | enum34>=1.1 5 | wmi>=1.4.9 6 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Unit tests for current project. 3 | Used "py.test" as a common tool for testing. 4 | """ 5 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include runner README.rst 2 | include runner LICENSE 3 | include requirements/default.txt 4 | include requirements/linux.txt 5 | include requirements/windows.txt 6 | recursive-exclude test * 7 | -------------------------------------------------------------------------------- /docs/modules/network.rst: -------------------------------------------------------------------------------- 1 | :mod:`network` -- Network monitor 2 | ================================= 3 | 4 | 5 | .. module:: network 6 | :platform: Unix, Windows, MacOS, POSIX 7 | :synopsis: Collect full information and statistics about network. 8 | .. moduleauthor:: Maxim Grischuk 9 | -------------------------------------------------------------------------------- /docs/modules/computer.rst: -------------------------------------------------------------------------------- 1 | :mod:`computer` -- General monitoring tool 2 | ========================================== 3 | 4 | 5 | .. module:: computer 6 | :platform: Unix, Windows, MacOS, POSIX 7 | :synopsis: Collect common information and statistics about computer. 8 | .. moduleauthor:: Maxim Grischuk 9 | -------------------------------------------------------------------------------- /docs/modules/convert.rst: -------------------------------------------------------------------------------- 1 | :mod:`convert` -- Convert monitoring values into human-readable format 2 | ====================================================================== 3 | 4 | 5 | .. module:: convert 6 | :platform: Unix, Windows, MacOS, POSIX 7 | :synopsis: Convert monitoring values into human-readable format. 8 | .. moduleauthor:: Maxim Grischuk 9 | -------------------------------------------------------------------------------- /test/test_convert.py: -------------------------------------------------------------------------------- 1 | from pyspectator.convert import UnitByte 2 | 3 | 4 | def test_get_name_reduction(): 5 | # Existing reduction 6 | reduction = UnitByte.get_name_reduction(UnitByte.megabyte) 7 | assert reduction == 'MB' 8 | # Non-existing reduction 9 | reduction = UnitByte.get_name_reduction('Non-existing reduction') 10 | assert reduction is None 11 | -------------------------------------------------------------------------------- /docs/modules/collection.rst: -------------------------------------------------------------------------------- 1 | :mod:`collection` -- Instruments for manipulating with statistics data 2 | ====================================================================== 3 | 4 | 5 | .. module:: collection 6 | :platform: Unix, Windows, MacOS, POSIX 7 | :synopsis: Provide instruments for manipulating with statistics data. 8 | .. moduleauthor:: Maxim Grischuk 9 | -------------------------------------------------------------------------------- /docs/modules/memory.rst: -------------------------------------------------------------------------------- 1 | :mod:`memory` -- Monitoring of virtual memory, swap and disk drive 2 | ================================================================== 3 | 4 | 5 | .. module:: memory 6 | :platform: Unix, Windows, MacOS, POSIX 7 | :synopsis: Collect full information and statistics about virtual memory, swap and disk drive. 8 | .. moduleauthor:: Maxim Grischuk 9 | -------------------------------------------------------------------------------- /docs/modules/processor.rst: -------------------------------------------------------------------------------- 1 | :mod:`processor` -- Monitoring of CPU and GPU 2 | ============================================= 3 | 4 | 5 | .. module:: processor 6 | :platform: Unix, Windows, MacOS, POSIX 7 | :synopsis: Collects full information and statistics about CPU and GPU. 8 | .. moduleauthor:: Maxim Grischuk 9 | 10 | 11 | .. automodule:: pyspectator.processor 12 | 13 | .. autoclass:: CPU 14 | :members: -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to pyspectator's documentation! 2 | ======================================= 3 | 4 | pyspectator is a Python cross-platform tool for monitoring resources of OS: CPU, memory, disk, network. 5 | 6 | 7 | 8 | Module Contents: 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | modules/computer.rst 14 | modules/processor.rst 15 | modules/memory.rst 16 | modules/network.rst 17 | modules/convert.rst 18 | modules/collection.rst 19 | 20 | 21 | 22 | Indices and tables 23 | ================== 24 | 25 | * :ref:`genindex` 26 | * :ref:`modindex` 27 | * :ref:`search` 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | MANIFEST 25 | 26 | # Installer logs 27 | pip-log.txt 28 | pip-delete-this-directory.txt 29 | 30 | # Unit test / coverage reports 31 | htmlcov/ 32 | .tox/ 33 | .coverage 34 | .cache 35 | nosetests.xml 36 | coverage.xml 37 | 38 | # Translations 39 | *.mo 40 | *.pot 41 | 42 | # Django stuff: 43 | *.log 44 | 45 | # Sphinx documentation 46 | docs/_build/ 47 | 48 | # IDE 49 | .idea/ 50 | 51 | # OS 52 | *~ 53 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflows will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: '3.x' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install setuptools wheel twine 25 | - name: Build and publish 26 | env: 27 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 28 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 29 | run: | 30 | python setup.py sdist bdist_wheel 31 | twine upload dist/* 32 | -------------------------------------------------------------------------------- /test/test_collection.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta, datetime 2 | from time import sleep 3 | import pytest 4 | from pyspectator.collection import LimitedTimeTable 5 | from pyvalid import ArgumentValidationError 6 | 7 | 8 | def test_limited_time_table(): 9 | time_span = timedelta(seconds=2) 10 | limited_time_table = LimitedTimeTable(time_span) 11 | assert len(limited_time_table) == 0 12 | with pytest.raises(ArgumentValidationError): 13 | limited_time_table[int()] = 'record #1' 14 | first_record_dtime = datetime.now() 15 | limited_time_table[first_record_dtime] = 'record #1' 16 | assert first_record_dtime in limited_time_table 17 | sleep(0.1) 18 | limited_time_table[datetime.now()] = 'record #2' 19 | assert len(limited_time_table) == 2 20 | with pytest.raises(ValueError): 21 | future = datetime.now() + timedelta(days=1) 22 | limited_time_table[future] = 'record #2' 23 | sleep(2.1) 24 | limited_time_table[datetime.now()] = 'record #3' 25 | assert len(limited_time_table) == 2 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Volodya Sirenko & Maxim Grischuk 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /pyspectator/convert.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class UnitByte(IntEnum): 5 | 6 | byte = 2 ** 0 7 | kilobyte = 2 ** 10 8 | megabyte = 2 ** 20 9 | gigabyte = 2 ** 30 10 | terabyte = 2 ** 40 11 | petabyte = 2 ** 50 12 | exabyte = 2 ** 60 13 | zettabyte = 2 ** 70 14 | yottabyte = 2 ** 80 15 | 16 | @staticmethod 17 | def convert(byte_value, unitbyte): 18 | converted_value = None 19 | if unitbyte in UnitByte: 20 | converted_value = byte_value / unitbyte.value 21 | return converted_value 22 | 23 | @staticmethod 24 | def auto_convert(byte_value): 25 | used_unitbyte = UnitByte.yottabyte 26 | converted_value = byte_value / UnitByte.yottabyte 27 | for unitbyte in UnitByte: 28 | temp_value = byte_value / unitbyte.value 29 | if temp_value < 1024: 30 | used_unitbyte = unitbyte 31 | converted_value = temp_value 32 | break 33 | return converted_value, used_unitbyte 34 | 35 | @staticmethod 36 | def get_name_reduction(unitbyte): 37 | reductions_en = { 38 | UnitByte.byte: 'B', 39 | UnitByte.kilobyte: 'KB', 40 | UnitByte.megabyte: 'MB', 41 | UnitByte.gigabyte: 'GB', 42 | UnitByte.terabyte: 'TB', 43 | UnitByte.petabyte: 'PB', 44 | UnitByte.exabyte: 'EB', 45 | UnitByte.zettabyte: 'ZB', 46 | UnitByte.yottabyte: 'YB' 47 | } 48 | return reductions_en.get(unitbyte) 49 | 50 | 51 | __all__ = ['UnitByte'] 52 | -------------------------------------------------------------------------------- /pyspectator/monitoring.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | from threading import Timer 3 | 4 | 5 | class AbcMonitor(metaclass=ABCMeta): 6 | """Base class for entities, which require repeating event. 7 | 8 | Attributes: 9 | monitoring (bool): indicator activity of monitor. 10 | monitoring_latency (int, float): frequency of execution monitor's 11 | action. 12 | """ 13 | 14 | def __init__(self, monitoring_latency): 15 | self.__monitoring_latency = None 16 | self.monitoring_latency = monitoring_latency 17 | self.__monitoring = False 18 | 19 | @property 20 | def monitoring(self): 21 | return self.__monitoring 22 | 23 | @property 24 | def monitoring_latency(self): 25 | return self.__monitoring_latency 26 | 27 | @monitoring_latency.setter 28 | def monitoring_latency(self, value): 29 | self.__monitoring_latency = value 30 | 31 | def start_monitoring(self): 32 | """Enable periodically monitoring. 33 | """ 34 | if self.__monitoring is False: 35 | self.__monitoring = True 36 | self.__monitoring_action() 37 | 38 | def stop_monitoring(self): 39 | """Disable periodically monitoring. 40 | """ 41 | self.__monitoring = False 42 | 43 | def __enter__(self): 44 | self.start_monitoring() 45 | 46 | def __exit__(self, exc_type, exc_val, exc_tb): 47 | self.stop_monitoring() 48 | 49 | def __monitoring_action(self): 50 | if self.__monitoring is True: 51 | self._monitoring_action() 52 | Timer(self.monitoring_latency, self.__monitoring_action).start() 53 | 54 | @abstractmethod 55 | def _monitoring_action(self): 56 | """Action, which repeated, when monitoring is enabled. 57 | """ 58 | raise NotImplementedError('Method not implemented by derived class!') 59 | 60 | 61 | __all__ = ['AbcMonitor'] 62 | -------------------------------------------------------------------------------- /pyspectator/temperature_reader.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | from os import path 3 | 4 | 5 | class LinuxCpuTemperatureReader(): 6 | files = [ 7 | '/sys/devices/LNXSYSTM:00/LNXTHERM:00/LNXTHERM:01/thermal_zone/temp', 8 | '/sys/bus/acpi/devices/LNXTHERM:00/thermal_zone/temp', 9 | '/proc/acpi/thermal_zone/THM0/temperature', 10 | '/proc/acpi/thermal_zone/THRM/temperature', 11 | '/proc/acpi/thermal_zone/THR1/temperature' 12 | ] 13 | 14 | @classmethod 15 | def get_reader(cls): 16 | readers = { 17 | cls.files[0]: cls.reader1, 18 | cls.files[1]: cls.reader1, 19 | cls.files[2]: cls.reader2, 20 | cls.files[3]: cls.reader2, 21 | cls.files[4]: cls.reader2 22 | } 23 | for file in cls.files: 24 | if path.exists(file): 25 | reader = readers.get(file) 26 | if reader: 27 | return reader(file) 28 | 29 | @classmethod 30 | def reader1(cls, file): 31 | def reader(file): 32 | temperature = open(file).read().strip() 33 | temperature = int(temperature) // 1000 34 | return temperature 35 | return partial(reader, file) 36 | 37 | @classmethod 38 | def reader2(cls, file): 39 | def reader(file): 40 | temperature = open(file).read().strip() 41 | temperature = temperature.lstrip('temperature :').rstrip(' C') 42 | return int(temperature) 43 | return partial(reader, file) 44 | 45 | 46 | class WindowsCpuTemperatureReader(): 47 | 48 | @classmethod 49 | def get_reader(cls): 50 | import wmi 51 | import pythoncom 52 | 53 | def temperature_reader(): 54 | pythoncom.CoInitialize() 55 | w = wmi.WMI(namespace='root\\wmi') 56 | temperature = w.MSAcpi_ThermalZoneTemperature()[0] 57 | temperature = int(temperature.CurrentTemperature / 10.0 - 273.15) 58 | return temperature 59 | return temperature_reader 60 | 61 | 62 | __all__ = ['LinuxCpuTemperatureReader', 'WindowsCpuTemperatureReader'] 63 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Summary 3 | ======= 4 | 5 | pyspectator is a Python cross-platform tool for monitoring resources of OS: CPU, memory, disk, network. 6 | 7 | 8 | ============ 9 | Requirements 10 | ============ 11 | 12 | - OS: Linux, Windows, FreeBSD, Solaris 13 | - Python version: 3.X 14 | - Packages: psutil, netifaces, wmi (only on Windows), enum34 (only on python 3.0.0 - 3.4.0) 15 | - For Windows OS Microsoft Visual C++ 10.0 or higher is required 16 | 17 | ============== 18 | How to install 19 | ============== 20 | 21 | Run as root user: 22 | 23 | .. code-block:: bash 24 | 25 | pip install pyspectator 26 | 27 | 28 | 29 | ================ 30 | Example of usage 31 | ================ 32 | 33 | There is simple project named `pyspectator_tornado `_ 34 | developed special for demonstration of pyspectator features. 35 | 36 | .. image:: http://i.imgur.com/yUjNlyQ.png 37 | :target: http://i.imgur.com/LFMmfHu.png 38 | :alt: General information 39 | 40 | .. image:: http://i.imgur.com/omNJhno.png 41 | :target: http://i.imgur.com/r0RuV2m.png 42 | :alt: CPU 43 | 44 | .. image:: http://i.imgur.com/qc3NwBa.png 45 | :target: http://i.imgur.com/zA7mteS.png 46 | :alt: Disk devices 47 | 48 | .. image:: http://i.imgur.com/Dugsnr6.png 49 | :target: http://i.imgur.com/rDadDzn.png 50 | :alt: Network 51 | 52 | 53 | 54 | ========== 55 | How to use 56 | ========== 57 | 58 | You can use pyspectator as module for your own project. Simple example of usage is presented in file "console.py". 59 | 60 | *NOTE: on Windows pyspectator can require elevated privileges.* 61 | 62 | Class "Computer" 63 | ---------------- 64 | 65 | .. code-block:: python 66 | 67 | >>> from pyspectator.computer import Computer 68 | >>> computer = Computer() 69 | >>> computer.os 70 | 'Linux 3.14.4-1-MANJARO' 71 | >>> computer.python_version 72 | 'CPython ver. 3.4.1' 73 | >>> computer.uptime 74 | '1:07:52' 75 | >>> computer.processor.name 76 | 'Intel(R) Core(TM) i3-3110M CPU @ 2.40GHz' 77 | 78 | 79 | Class "Cpu" 80 | ----------- 81 | 82 | 83 | .. code-block:: python 84 | 85 | >>> from pyspectator.processor import Cpu 86 | >>> from time import sleep 87 | >>> cpu = Cpu(monitoring_latency=1) 88 | >>> with cpu: 89 | ... for _ in range(8): 90 | ... cpu.load, cpu.temperature 91 | ... sleep(1.1) 92 | ... 93 | (22.6, 55) 94 | (6.1, 55) 95 | (5.5, 54) 96 | (7.1, 54) 97 | (5.6, 54) 98 | (7.0, 54) 99 | (10.2, 54) 100 | (6.6, 54) 101 | -------------------------------------------------------------------------------- /pyspectator/collection.py: -------------------------------------------------------------------------------- 1 | from collections import MutableMapping, Container 2 | from datetime import datetime, timedelta 3 | from pyvalid import accepts 4 | 5 | 6 | class LimitedTimeTable(MutableMapping, Container): 7 | 8 | def __init__(self, time_span): 9 | self.__storage = dict() 10 | self.__time_span = None 11 | self.time_span = time_span 12 | 13 | @property 14 | def time_span(self): 15 | return self.__time_span 16 | 17 | @time_span.setter 18 | @accepts(object, timedelta) 19 | def time_span(self, value): 20 | self.__time_span = value 21 | 22 | @property 23 | def oldest(self): 24 | value = None 25 | if self.__len__() > 0: 26 | value = min(self.__storage.keys()) 27 | return value 28 | 29 | @property 30 | def newest(self): 31 | value = None 32 | if self.__len__() > 0: 33 | value = max(self.__storage.keys()) 34 | return value 35 | 36 | def oldest_keys(self, size): 37 | for key in self.__get_slice(0, size): 38 | yield key 39 | 40 | def oldest_values(self, size): 41 | for key in self.oldest_keys(size): 42 | yield self.__storage.get(key) 43 | 44 | def oldest_items(self, size): 45 | for key in self.oldest_keys(size): 46 | yield (key, self.__storage.get(key)) 47 | 48 | def newest_keys(self, size): 49 | for key in self.__get_slice(-size, None): 50 | yield key 51 | 52 | def newest_values(self, size): 53 | for key in self.newest_keys(size): 54 | yield self.__storage.get(key) 55 | 56 | def newest_items(self, size): 57 | for key in self.newest_keys(size): 58 | yield (key, self.__storage.get(key)) 59 | 60 | def __get_slice(self, start, end): 61 | keys = sorted(self.keys()) 62 | return keys[start:end] 63 | 64 | def __getitem__(self, item): 65 | return self.__storage.__getitem__(item) 66 | 67 | @accepts(object, datetime, object) 68 | def __setitem__(self, key, value): 69 | now = datetime.now() 70 | if key > now: 71 | raise ValueError('Can\'t set item from future!') 72 | oldest = self.oldest 73 | if (oldest is not None) and (oldest != key): 74 | longest_time_span = now - oldest 75 | # Item is too old for current timetable 76 | if longest_time_span >= self.time_span: 77 | self.__delitem__(oldest) 78 | return self.__storage.__setitem__(key, value) 79 | 80 | def __delitem__(self, key): 81 | return self.__storage.__delitem__(key) 82 | 83 | def __len__(self): 84 | return self.__storage.__len__() 85 | 86 | def __iter__(self): 87 | return self.__storage.__iter__() 88 | 89 | def __contains__(self, item): 90 | return self.__storage.__contains__(item) 91 | 92 | 93 | __all__ = ['LimitedTimeTable'] 94 | -------------------------------------------------------------------------------- /console.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import platform 3 | from os import linesep 4 | from time import sleep 5 | from pyspectator.convert import UnitByte 6 | 7 | 8 | CLEAR_CMD = 'cls' if platform.system() == 'Windows' else 'clear' 9 | 10 | 11 | def clear(): 12 | subprocess.call(CLEAR_CMD, shell=True) 13 | 14 | 15 | def print_hr(space_before=False, space_after=False): 16 | before = linesep if space_before else '' 17 | after = linesep if space_after else '' 18 | print(before + '-' * 80 + after) 19 | 20 | 21 | class Format(object): 22 | 23 | @staticmethod 24 | def temperature(value): 25 | formatted_value = '' 26 | if isinstance(value, (int, float)): 27 | formatted_value = str(value) + '°C' 28 | return formatted_value 29 | 30 | @staticmethod 31 | def byte_value(value): 32 | formatted_value = '' 33 | if isinstance(value, (int, float)): 34 | value, unit = UnitByte.auto_convert(value) 35 | value = '{:.2f}'.format(value) 36 | unit = UnitByte.get_name_reduction(unit) 37 | formatted_value = value + unit 38 | return formatted_value 39 | 40 | @staticmethod 41 | def percent(value): 42 | formatted_value = '' 43 | if isinstance(value, (int, float)): 44 | formatted_value = str(value) + '%' 45 | return formatted_value 46 | 47 | 48 | def main(computer): 49 | print('Start monitoring system...') 50 | print_hr(space_after=True) 51 | # Show system info for ~16 seconds 52 | for _ in range(16): 53 | clear() 54 | # Display general information about computer 55 | print('OS: ' + str(computer.os)) 56 | print('Boot time: {}; Uptime: {}'.format( 57 | computer.boot_time, computer.uptime 58 | )) 59 | print('') 60 | # Display CPU info 61 | print('CPU name: ' + str(computer.processor.name)) 62 | print('Amount of CPU cores: ' + str(computer.processor.count)) 63 | print('CPU load: ' + Format.percent(computer.processor.load)) 64 | cpu_temperature = 'unknown' 65 | if computer.processor.temperature is not None: 66 | cpu_temperature = Format.temperature( 67 | computer.processor.temperature 68 | ) 69 | print('CPU temperature: ' + cpu_temperature) 70 | print('') 71 | # Display network info 72 | print('Hostname: ' + str(computer.hostname)) 73 | print('Network interface: ' + str(computer.network_interface.name)) 74 | print('MAC: ' + str(computer.network_interface.hardware_address)) 75 | print('IP: {}; Mask: {}; Gateway: {}'.format( 76 | computer.network_interface.ip_address, 77 | computer.network_interface.subnet_mask, 78 | computer.network_interface.default_route 79 | )) 80 | print('Sent data: {}; Received data: {}'.format( 81 | Format.byte_value(computer.network_interface.bytes_sent), 82 | Format.byte_value(computer.network_interface.bytes_recv) 83 | )) 84 | print('') 85 | # Display virtual memory info 86 | print('Virtual memory: use {} from {}, {}'.format( 87 | Format.byte_value(computer.virtual_memory.available), 88 | Format.byte_value(computer.virtual_memory.total), 89 | Format.percent(computer.virtual_memory.used_percent) 90 | )) 91 | print('') 92 | # Display nonvolatile memory info 93 | output_format1 = '{:_^16}{:_^16}{:_^16}{:_^16}{:_^16}' 94 | output_format2 = '{: ^16}{: ^16}{: ^16}{: ^16}{: ^16}' 95 | print(output_format1.format('Device', 'Total', 'Use', 'Type', 'Mount')) 96 | for dev in computer.nonvolatile_memory: 97 | output_text = output_format2.format( 98 | dev.device, 99 | Format.byte_value(dev.total), 100 | Format.percent(dev.used_percent), 101 | dev.fstype, 102 | dev.mountpoint 103 | ) 104 | print(output_text) 105 | sleep(1) 106 | print_hr(space_before=True) 107 | print('Shutdown monitoring system...') 108 | 109 | 110 | if __name__ == '__main__': 111 | # Initialize computer instance 112 | from pyspectator.computer import Computer 113 | COMPUTER = Computer() 114 | # Start monitoring system 115 | with COMPUTER: 116 | # Start console interface 117 | main(COMPUTER) 118 | -------------------------------------------------------------------------------- /pyspectator/network.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from datetime import timedelta, datetime 3 | import psutil 4 | import netifaces as nif 5 | from pyspectator.monitoring import AbcMonitor 6 | from pyspectator.collection import LimitedTimeTable 7 | 8 | 9 | class NetworkInterface(AbcMonitor): 10 | 11 | def __init__(self, monitoring_latency, stats_interval=None, 12 | ip_address=None): 13 | super().__init__(monitoring_latency) 14 | self.__name = None 15 | self.__hardware_address = None 16 | if ip_address is None: 17 | ip_address = NetworkInterface.__get_active_ip_address() 18 | self.__ip_address = ip_address 19 | self.__broadcast_address = None 20 | self.__subnet_mask = None 21 | self.__default_route = None 22 | self.__bytes_sent = 0 23 | self.__bytes_recv = 0 24 | # Get interface name, network mask and broadcast address 25 | if self.__ip_address is not None: 26 | for interface in nif.interfaces(): 27 | addresses = nif.ifaddresses(interface) 28 | try: 29 | af_inet = addresses[nif.AF_INET][0] 30 | if af_inet['addr'] != self.__ip_address: 31 | continue 32 | af_link = addresses[nif.AF_LINK][0] 33 | self.__name = NetworkInterface.__check_interface_name( 34 | interface 35 | ) 36 | self.__hardware_address = af_link['addr'] 37 | self.__broadcast_address = af_inet['broadcast'] 38 | self.__subnet_mask = af_inet['netmask'] 39 | break 40 | except (IndexError, KeyError): 41 | # ignore interfaces, which don't have MAC or IP 42 | continue 43 | # Get gateway address 44 | if self.name is not None: 45 | for gateway_info in nif.gateways()[nif.AF_INET]: 46 | if self.name in gateway_info: 47 | self.__default_route = gateway_info[0] 48 | break 49 | # Prepare to collect statistics 50 | if stats_interval is None: 51 | stats_interval = timedelta(hours=1) 52 | self.__bytes_sent_stats = LimitedTimeTable(stats_interval) 53 | self.__bytes_recv_stats = LimitedTimeTable(stats_interval) 54 | # Read updating values at first time 55 | self._monitoring_action() 56 | 57 | @property 58 | def name(self): 59 | return self.__name 60 | 61 | @property 62 | def hardware_address(self): 63 | return self.__hardware_address 64 | 65 | @property 66 | def ip_address(self): 67 | return self.__ip_address 68 | 69 | @property 70 | def broadcast_address(self): 71 | return self.__broadcast_address 72 | 73 | @property 74 | def subnet_mask(self): 75 | return self.__subnet_mask 76 | 77 | @property 78 | def default_route(self): 79 | return self.__default_route 80 | 81 | @property 82 | def bytes_sent(self): 83 | return self.__bytes_sent 84 | 85 | @property 86 | def bytes_recv(self): 87 | return self.__bytes_recv 88 | 89 | @property 90 | def bytes_sent_stats(self): 91 | return self.__bytes_sent_stats 92 | 93 | @property 94 | def bytes_recv_stats(self): 95 | return self.__bytes_recv_stats 96 | 97 | @classmethod 98 | def __check_interface_name(cls, name): 99 | net_io = psutil.net_io_counters(pernic=True) 100 | if name in net_io: 101 | return name 102 | for curr_nif_name in net_io: 103 | if name in curr_nif_name: 104 | name = curr_nif_name 105 | break 106 | return name 107 | 108 | @classmethod 109 | def __get_active_ip_address(cls): 110 | ip_address = None 111 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 112 | try: 113 | s.connect(('8.8.8.8', 80)) 114 | ip_address = s.getsockname()[0] 115 | except: 116 | s.close() 117 | return ip_address 118 | 119 | def _monitoring_action(self): 120 | net_io = psutil.net_io_counters(pernic=True) 121 | if self.name in net_io: 122 | net_io = net_io[self.name] 123 | now = datetime.now() 124 | self.__bytes_sent = net_io.bytes_sent 125 | self.__bytes_recv_stats[now] = self.bytes_sent 126 | self.__bytes_recv = net_io.bytes_recv 127 | self.__bytes_recv_stats[now] = self.bytes_recv 128 | 129 | 130 | __all__ = ['NetworkInterface'] 131 | -------------------------------------------------------------------------------- /pyspectator/computer.py: -------------------------------------------------------------------------------- 1 | import platform 2 | from datetime import datetime 3 | import psutil 4 | from pyspectator.monitoring import AbcMonitor 5 | from pyspectator.memory import NonvolatileMemory, VirtualMemory, SwapMemory 6 | from pyspectator.processor import Cpu 7 | from pyspectator.network import NetworkInterface 8 | 9 | 10 | class Computer(AbcMonitor): 11 | 12 | def __init__(self): 13 | self.datetime_format = '%H:%M:%S %d/%m/%Y' 14 | self.__raw_boot_time = psutil.boot_time() 15 | self.__boot_time = datetime.fromtimestamp(self.raw_boot_time) 16 | self.__boot_time = self.__boot_time.strftime(self.datetime_format) 17 | self.__hostname = platform.node() 18 | self.__os = Computer.__get_os_name() 19 | self.__architecture = platform.machine() 20 | self.__python_version = '{} ver. {}'.format( 21 | platform.python_implementation(), platform.python_version() 22 | ) 23 | self.__processor = Cpu(monitoring_latency=1) 24 | self.__nonvolatile_memory = NonvolatileMemory.instances_connected_devices(monitoring_latency=10) 25 | self.__nonvolatile_memory_devices = set( 26 | [dev_info.device for dev_info in self.__nonvolatile_memory] 27 | ) 28 | self.__virtual_memory = VirtualMemory(monitoring_latency=1) 29 | self.__swap_memory = SwapMemory(monitoring_latency=1) 30 | self.__network_interface = NetworkInterface(monitoring_latency=3) 31 | super().__init__(monitoring_latency=3) 32 | 33 | @property 34 | def processor(self): 35 | return self.__processor 36 | 37 | @property 38 | def raw_boot_time(self): 39 | return self.__raw_boot_time 40 | 41 | @property 42 | def boot_time(self): 43 | return self.__boot_time 44 | 45 | @property 46 | def raw_uptime(self): 47 | return datetime.now() - datetime.fromtimestamp(self.raw_boot_time) 48 | 49 | @property 50 | def uptime(self): 51 | return str(self.raw_uptime).split('.')[0] 52 | 53 | @property 54 | def os(self): 55 | return self.__os 56 | 57 | @property 58 | def architecture(self): 59 | return self.__architecture 60 | 61 | @property 62 | def python_version(self): 63 | return self.__python_version 64 | 65 | @property 66 | def hostname(self): 67 | return self.__hostname 68 | 69 | @property 70 | def nonvolatile_memory(self): 71 | return self.__nonvolatile_memory 72 | 73 | @property 74 | def virtual_memory(self): 75 | return self.__virtual_memory 76 | 77 | @property 78 | def swap_memory(self): 79 | return self.__swap_memory 80 | 81 | @property 82 | def network_interface(self): 83 | return self.__network_interface 84 | 85 | @classmethod 86 | def __get_os_name(cls): 87 | system = '{} {}'.format(platform.system(), platform.release()).strip() 88 | if 'Linux' in system: 89 | import distro 90 | system = ' '.join(distro.linux_distribution()).strip() 91 | return system 92 | 93 | def _monitoring_action(self): 94 | # Look for connected & ejected nonvolatile memory devices 95 | for dev in self.nonvolatile_memory: 96 | if not dev.is_alive: 97 | dev.stop_monitoring() 98 | self.__nonvolatile_memory_devices.remove(dev.device) 99 | self.__nonvolatile_memory.remove(dev) 100 | connected_dev = set(NonvolatileMemory.names_connected_devices()) - \ 101 | self.__nonvolatile_memory_devices 102 | for dev_name in connected_dev: 103 | dev = NonvolatileMemory(monitoring_latency=10, device=dev_name) 104 | self.__nonvolatile_memory.append(dev) 105 | self.__nonvolatile_memory_devices.add(dev_name) 106 | 107 | def start_monitoring(self, all_components=True): 108 | super().start_monitoring() 109 | if all_components: 110 | self.processor.start_monitoring() 111 | for mem in self.nonvolatile_memory: 112 | mem.start_monitoring() 113 | self.virtual_memory.start_monitoring() 114 | self.network_interface.start_monitoring() 115 | 116 | def stop_monitoring(self, all_components=True): 117 | if all_components: 118 | self.processor.stop_monitoring() 119 | for mem in self.nonvolatile_memory: 120 | mem.stop_monitoring() 121 | self.virtual_memory.stop_monitoring() 122 | self.network_interface.stop_monitoring() 123 | super().stop_monitoring() 124 | 125 | def __enter__(self): 126 | self.start_monitoring() 127 | 128 | def __exit__(self, exc_type, exc_val, exc_tb): 129 | self.stop_monitoring() 130 | 131 | 132 | __all__ = ['Computer'] 133 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import platform 3 | import os 4 | from setuptools import setup 5 | from setuptools.command.test import test as TestCommand 6 | 7 | 8 | class PyTest(TestCommand): 9 | """ 10 | Test-runner 11 | """ 12 | 13 | user_options = [('pytest-args=', 'a', 'Arguments to pass to py.test')] 14 | 15 | def __init__(self, *args, **kwargs): 16 | super(PyTest, self).__init__(*args, **kwargs) 17 | self.pytest_args = None 18 | self.test_suite = None 19 | 20 | def initialize_options(self): 21 | TestCommand.initialize_options(self) 22 | self.pytest_args = list() 23 | 24 | def finalize_options(self): 25 | TestCommand.finalize_options(self) 26 | self.test_args = list() 27 | self.test_suite = True 28 | 29 | def run_tests(self): 30 | # import here, cause outside the eggs aren't loaded 31 | import pytest 32 | err_no = pytest.main(self.pytest_args) 33 | sys.exit(err_no) 34 | 35 | 36 | def main(): 37 | # Check python version 38 | if sys.version_info < (3, 0, 0): 39 | sys.stderr.write( 40 | 'You need python 3.0 or later to run this script!' + os.linesep 41 | ) 42 | exit(1) 43 | # Generate requires 44 | if 'Windows' in platform.system(): 45 | requirements_file = 'windows.txt' 46 | elif 'Linux' in platform.system(): 47 | requirements_file = 'linux.txt' 48 | else: 49 | requirements_file = 'default.txt' 50 | requirements_file = os.path.join('requirements', requirements_file) 51 | with open(requirements_file) as requirements_reader: 52 | requires = requirements_reader.read().splitlines() 53 | # Get package description 54 | with open('README.rst') as readme_reader: 55 | long_description = readme_reader.read() 56 | # Describe installer 57 | settings = { 58 | 'name': 'pyspectator', 59 | 'version': '1.2.2', 60 | 'author': 'Maxim Grischuk', 61 | 'author_email': 'uzumaxy@gmail.com', 62 | 'maintainer': 'Maxim Grischuk', 63 | 'maintainer_email': 'uzumaxy@gmail.com', 64 | 'packages': ['pyspectator'], 65 | 'url': 'https://github.com/it-geeks-club/pyspectator', 66 | 'download_url': 'https://github.com/it-geeks-club/pyspectator/releases', 67 | 'license': 'BSD', 68 | 'description': 'pyspectator is a Python cross-platform tool for ' 69 | 'monitoring OS resources.', 70 | 'long_description': long_description, 71 | 'install_requires': requires, 72 | 'keywords': [ 73 | 'pyspectator', 'spectator', 74 | 'monitoring', 'tool', 75 | 'statistic', 'stats', 76 | 'computer', 'pc', 'server', 77 | 'mem', 'memory', 78 | 'network', 'net', 'io', 79 | 'processor', 'cpu', 80 | 'hdd', 'hard', 'disk', 'drive' 81 | ], 82 | 'platforms': 'Platform Independent', 83 | 'package_data': { 84 | 'pyspectator': ['LICENSE', 'README.rst'] 85 | }, 86 | 'scripts': ['console.py'], 87 | 'tests_require': ['pytest>=2.6.2'], 88 | 'cmdclass': {'test': PyTest}, 89 | 'classifiers': [ 90 | 'Development Status :: 5 - Production/Stable', 91 | 'Environment :: Console', 92 | 'Environment :: MacOS X', 93 | 'Environment :: Win32 (MS Windows)', 94 | 'Intended Audience :: Developers', 95 | 'Intended Audience :: Information Technology', 96 | 'Intended Audience :: System Administrators', 97 | 'License :: OSI Approved :: BSD License', 98 | 'Natural Language :: English', 99 | 'Operating System :: OS Independent', 100 | 'Operating System :: MacOS', 101 | 'Operating System :: Microsoft :: Windows', 102 | 'Operating System :: POSIX :: Linux', 103 | 'Operating System :: POSIX', 104 | 'Operating System :: Unix', 105 | 'Programming Language :: C', 106 | 'Programming Language :: Python :: 3', 107 | 'Programming Language :: Python :: 3.0', 108 | 'Programming Language :: Python :: 3.1', 109 | 'Programming Language :: Python :: 3.2', 110 | 'Programming Language :: Python :: 3.3', 111 | 'Programming Language :: Python :: 3.4', 112 | 'Programming Language :: Python :: 3.5', 113 | 'Programming Language :: Python :: 3.6', 114 | 'Programming Language :: Python :: 3.7', 115 | 'Programming Language :: Python :: 3.8', 116 | 'Programming Language :: Python :: 3.9', 117 | 'Programming Language :: Python :: Implementation :: CPython', 118 | 'Programming Language :: Python', 119 | 'Topic :: Software Development :: Libraries :: Python Modules', 120 | 'Topic :: Software Development :: Libraries', 121 | 'Topic :: System :: Benchmark', 122 | 'Topic :: System :: Hardware', 123 | 'Topic :: System :: Monitoring', 124 | 'Topic :: System :: Networking :: Monitoring', 125 | 'Topic :: System :: Networking', 126 | 'Topic :: System :: Systems Administration', 127 | 'Topic :: Utilities', 128 | ], 129 | } 130 | setup(**settings) 131 | 132 | 133 | if __name__ == '__main__': 134 | main() 135 | -------------------------------------------------------------------------------- /pyspectator/memory.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | from datetime import timedelta, datetime 3 | import psutil 4 | from pyspectator.monitoring import AbcMonitor 5 | from pyspectator.collection import LimitedTimeTable 6 | 7 | 8 | class AbsMemory(AbcMonitor, metaclass=ABCMeta): 9 | 10 | def __init__(self, monitoring_latency, stats_interval=None): 11 | # Prepare to collect statistic 12 | if stats_interval is None: 13 | stats_interval = timedelta(hours=1) 14 | self.__available_stats = LimitedTimeTable(stats_interval) 15 | self.__used_percent_stats = LimitedTimeTable(stats_interval) 16 | # Get info about total and available memory 17 | try: 18 | self.__total = self._get_total_memory() 19 | self.__available = self._get_available_memory() 20 | now = datetime.now() 21 | self.__available_stats[now] = self.available 22 | self.__used_percent_stats[now] = self.used_percent 23 | except: 24 | self.__total = None 25 | self.__available = None 26 | self.__available_stats.clear() 27 | self.__used_percent_stats.clear() 28 | # Init base class 29 | super().__init__(monitoring_latency) 30 | 31 | @property 32 | def total(self): 33 | return self.__total 34 | 35 | @property 36 | def available(self): 37 | return self.__available 38 | 39 | @property 40 | def used(self): 41 | used_mem = None 42 | if (self.total is not None) and (self.available is not None): 43 | used_mem = self.total - self.available 44 | return used_mem 45 | 46 | @property 47 | def used_percent(self): 48 | percent = None 49 | used = self.used 50 | if used is not None: 51 | percent = int(used / self.total * 100) 52 | return percent 53 | 54 | @property 55 | def available_stats(self): 56 | return self.__available_stats 57 | 58 | @property 59 | def used_percent_stats(self): 60 | return self.__used_percent_stats 61 | 62 | def _monitoring_action(self): 63 | try: 64 | self.__available = self._get_available_memory() 65 | now = datetime.now() 66 | self.__available_stats[now] = self.available 67 | self.__used_percent_stats[now] = self.used_percent 68 | except: 69 | self.__available = None 70 | self.__available_stats.clear() 71 | self.__used_percent_stats.clear() 72 | self.stop_monitoring() 73 | 74 | @abstractmethod 75 | def _get_total_memory(self): 76 | raise NotImplementedError('Method not implemented by derived class!') 77 | 78 | @abstractmethod 79 | def _get_available_memory(self): 80 | raise NotImplementedError('Method not implemented by derived class!') 81 | 82 | 83 | class VirtualMemory(AbsMemory): 84 | 85 | def __init__(self, monitoring_latency): 86 | super().__init__(monitoring_latency) 87 | 88 | def _get_available_memory(self): 89 | return psutil.virtual_memory().available 90 | 91 | def _get_total_memory(self): 92 | return psutil.virtual_memory().total 93 | 94 | 95 | class SwapMemory(AbsMemory): 96 | 97 | def __init__(self, monitoring_latency): 98 | super().__init__(monitoring_latency) 99 | 100 | def _get_available_memory(self): 101 | return psutil.swap_memory().free 102 | 103 | def _get_total_memory(self): 104 | return psutil.swap_memory().total 105 | 106 | 107 | class NonvolatileMemory(AbsMemory): 108 | 109 | def __init__(self, monitoring_latency, device): 110 | dev_info = None 111 | for current_dev_info in psutil.disk_partitions(): 112 | if current_dev_info.device == device: 113 | dev_info = current_dev_info 114 | break 115 | if dev_info is None: 116 | raise DeviceNotFoundException( 117 | 'Device {} not found!'.format(device) 118 | ) 119 | self.__is_alive = True 120 | self.__device = device 121 | self.__mountpoint = dev_info.mountpoint 122 | self.__fstype = dev_info.fstype 123 | super().__init__(monitoring_latency) 124 | 125 | @property 126 | def device(self): 127 | return self.__device 128 | 129 | @property 130 | def mountpoint(self): 131 | return self.__mountpoint 132 | 133 | @property 134 | def fstype(self): 135 | return self.__fstype 136 | 137 | @property 138 | def is_alive(self): 139 | return self.__is_alive 140 | 141 | def _get_available_memory(self): 142 | return psutil.disk_usage(self.mountpoint).free 143 | 144 | def _get_total_memory(self): 145 | return psutil.disk_usage(self.mountpoint).total 146 | 147 | def _monitoring_action(self): 148 | devices = NonvolatileMemory.names_connected_devices() 149 | self.__is_alive = self.device not in devices 150 | if self.is_alive: 151 | super()._monitoring_action() 152 | 153 | @staticmethod 154 | def instances_connected_devices(monitoring_latency): 155 | devices = list() 156 | for current_dev_info in psutil.disk_partitions(): 157 | current_dev = NonvolatileMemory( 158 | monitoring_latency, current_dev_info.device 159 | ) 160 | devices.append(current_dev) 161 | return devices 162 | 163 | @staticmethod 164 | def names_connected_devices(): 165 | return [dev_info.device for dev_info in psutil.disk_partitions()] 166 | 167 | 168 | class DeviceNotFoundException(Exception): 169 | pass 170 | 171 | 172 | __all__ = [ 173 | 'AbsMemory', 174 | 'VirtualMemory', 175 | 'SwapMemory', 176 | 'NonvolatileMemory', 177 | 'DeviceNotFoundException' 178 | ] 179 | -------------------------------------------------------------------------------- /pyspectator/processor.py: -------------------------------------------------------------------------------- 1 | import platform 2 | import os 3 | import subprocess 4 | import re 5 | from collections import Callable 6 | from datetime import datetime, timedelta 7 | import psutil 8 | from pyspectator.monitoring import AbcMonitor 9 | from pyspectator.collection import LimitedTimeTable 10 | from pyspectator.temperature_reader import LinuxCpuTemperatureReader 11 | from pyspectator.temperature_reader import WindowsCpuTemperatureReader 12 | 13 | 14 | class Cpu(AbcMonitor): 15 | """Monitoring system of the Central Processing Unit. 16 | 17 | :param monitoring_latency: time interval (in seconds) between calls of 18 | the CPU scanner. 19 | :type monitoring_latency: int, float 20 | :param stats_interval: time interval (in seconds) between calls of the 21 | statistics collector. 22 | :type stats_interval: int, float 23 | 24 | Usage example: 25 | 26 | .. code-block:: python 27 | 28 | >>> from pyspectator.processor import Cpu 29 | >>> from time import sleep 30 | >>> cpu = Cpu(monitoring_latency=1) 31 | >>> cpu.name 32 | 'Intel(R) Core(TM)2 Duo CPU T6570 @ 2.10GHz' 33 | >>> cpu.count 34 | 2 35 | >>> with cpu: 36 | ... for _ in range(8): 37 | ... cpu.load, cpu.temperature 38 | ... sleep(1.1) 39 | ... 40 | (22.6, 55) 41 | (6.1, 55) 42 | (5.5, 54) 43 | (7.1, 54) 44 | (5.6, 54) 45 | (7.0, 54) 46 | (10.2, 54) 47 | (6.6, 54) 48 | """ 49 | 50 | def __init__(self, monitoring_latency, stats_interval=None): 51 | super().__init__(monitoring_latency) 52 | self.__name = Cpu.__get_processor_name() 53 | self.__count = psutil.cpu_count() 54 | self.__load = None 55 | self.__temperature = None 56 | # Init temperature reader 57 | self.__temperature_reader = Cpu.__get_processor_temperature_reader() 58 | # Prepare to collect statistics 59 | if stats_interval is None: 60 | stats_interval = timedelta(hours=1) 61 | self.__load_stats = LimitedTimeTable(stats_interval) 62 | self.__temperature_stats = LimitedTimeTable(stats_interval) 63 | # Read updating value at first time 64 | self._monitoring_action() 65 | 66 | @property 67 | def name(self): 68 | """Full name of the CPU. 69 | 70 | :getter: Return full name of the CPU. Return ``None`` if undetermined. 71 | :setter: Not available. 72 | :type: string, None 73 | """ 74 | return self.__name 75 | 76 | @property 77 | def count(self): 78 | """Amount of a CPU cores. 79 | 80 | :getter: Return the number of logical CPUs in the system. Return 81 | ``None`` if undetermined. 82 | :setter: Not available. 83 | :type: int, None 84 | """ 85 | return self.__count 86 | 87 | @property 88 | def load(self): 89 | """CPU load in percent. 90 | 91 | :getter: Return CPU load in percent. From 0.00 to 100.00 or ``None`` 92 | if undetermined. 93 | :setter: Not available. 94 | :type: float, None 95 | """ 96 | return self.__load 97 | 98 | @property 99 | def temperature(self): 100 | """Temperature (in Celsius) of the CPU. 101 | 102 | :getter: Return temperature (in Celsius) of the CPU. Return ``None`` 103 | if undetermined. 104 | :setter: Not available. 105 | :type: int, None 106 | """ 107 | return self.__temperature 108 | 109 | @property 110 | def load_stats(self): 111 | """Statistics about CPU load. 112 | 113 | :getter: Return statistics about CPU load. 114 | :setter: Not available. 115 | :type: pyspectator.collection.LimitedTimeTable 116 | """ 117 | return self.__load_stats 118 | 119 | @property 120 | def temperature_stats(self): 121 | """Statistics about CPU temperature. 122 | 123 | :getter: Return statistics about CPU temperature. 124 | :setter: Not available. 125 | :type: pyspectator.collection.LimitedTimeTable 126 | """ 127 | return self.__temperature_stats 128 | 129 | def _monitoring_action(self): 130 | now = datetime.now() 131 | self.__load = psutil.cpu_percent() 132 | self.__load_stats[now] = self.__load 133 | if isinstance(self.__temperature_reader, Callable): 134 | try: 135 | self.__temperature = self.__temperature_reader() 136 | self.__temperature_stats[now] = self.__temperature 137 | except: 138 | print('Can\'t read CPU temperature') 139 | 140 | @classmethod 141 | def __get_processor_name(cls): 142 | cpu_name = None 143 | os_name = platform.system() 144 | if os_name == 'Windows': 145 | cpu_name = platform.processor() 146 | elif os_name == 'Darwin': 147 | os.environ['PATH'] = os.environ['PATH'] + os.pathsep + '/usr/sbin' 148 | command = ('sysctl', '-n', 'machdep.cpu.brand_string') 149 | output = subprocess.check_output(command) 150 | if output: 151 | cpu_name = output.decode().strip() 152 | elif os_name == 'Linux': 153 | all_info = subprocess.check_output('cat /proc/cpuinfo', shell=True) 154 | all_info = all_info.strip().split(os.linesep.encode()) 155 | for line in all_info: 156 | line = line.decode() 157 | if 'model name' not in line: 158 | continue 159 | cpu_name = re.sub('.*model name.*:', str(), line, 1).strip() 160 | break 161 | return cpu_name 162 | 163 | @classmethod 164 | def __get_processor_temperature_reader(cls): 165 | reader = None 166 | os_name = platform.system() 167 | if os_name == 'Windows': 168 | reader = WindowsCpuTemperatureReader.get_reader() 169 | elif os_name == 'Darwin': 170 | # TODO: try to use C lib - https://github.com/lavoiesl/osx-cpu-temp 171 | pass 172 | elif os_name == 'Linux': 173 | reader = LinuxCpuTemperatureReader.get_reader() 174 | return reader 175 | 176 | 177 | __all__ = ['Cpu'] 178 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | 3 | # 4 | 5 | # You can set these variables from the command line. 6 | SPHINXOPTS = 7 | SPHINXBUILD = sphinx-build 8 | PAPER = 9 | BUILDDIR = _build 10 | 11 | # User-friendly check for sphinx-build 12 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 13 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 14 | endif 15 | 16 | # Internal variables. 17 | PAPEROPT_a4 = -D latex_paper_size=a4 18 | PAPEROPT_letter = -D latex_paper_size=letter 19 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 20 | # the i18n builder cannot share the environment and doctrees with the others 21 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 22 | 23 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 24 | 25 | help: 26 | @echo "Please use \`make ' where is one of" 27 | @echo " html to make standalone HTML files" 28 | @echo " dirhtml to make HTML files named index.html in directories" 29 | @echo " singlehtml to make a single large HTML file" 30 | @echo " pickle to make pickle files" 31 | @echo " json to make JSON files" 32 | @echo " htmlhelp to make HTML files and a HTML help project" 33 | @echo " qthelp to make HTML files and a qthelp project" 34 | @echo " devhelp to make HTML files and a Devhelp project" 35 | @echo " epub to make an epub" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | 50 | clean: 51 | rm -rf $(BUILDDIR)/* 52 | 53 | html: 54 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 55 | @echo 56 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 57 | 58 | dirhtml: 59 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 60 | @echo 61 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 62 | 63 | singlehtml: 64 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 65 | @echo 66 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 67 | 68 | pickle: 69 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 70 | @echo 71 | @echo "Build finished; now you can process the pickle files." 72 | 73 | json: 74 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 75 | @echo 76 | @echo "Build finished; now you can process the JSON files." 77 | 78 | htmlhelp: 79 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 80 | @echo 81 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 82 | ".hhp project file in $(BUILDDIR)/htmlhelp." 83 | 84 | qthelp: 85 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 86 | @echo 87 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 88 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 89 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pyspectator.qhcp" 90 | @echo "To view the help file:" 91 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pyspectator.qhc" 92 | 93 | devhelp: 94 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 95 | @echo 96 | @echo "Build finished." 97 | @echo "To view the help file:" 98 | @echo "# mkdir -p $$HOME/.local/share/devhelp/pyspectator" 99 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pyspectator" 100 | @echo "# devhelp" 101 | 102 | epub: 103 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 104 | @echo 105 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 106 | 107 | latex: 108 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 109 | @echo 110 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 111 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 112 | "(use \`make latexpdf' here to do that automatically)." 113 | 114 | latexpdf: 115 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 116 | @echo "Running LaTeX files through pdflatex..." 117 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 118 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 119 | 120 | latexpdfja: 121 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 122 | @echo "Running LaTeX files through platex and dvipdfmx..." 123 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 124 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 125 | 126 | text: 127 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 128 | @echo 129 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 130 | 131 | man: 132 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 133 | @echo 134 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 135 | 136 | texinfo: 137 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 138 | @echo 139 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 140 | @echo "Run \`make' in that directory to run these through makeinfo" \ 141 | "(use \`make info' here to do that automatically)." 142 | 143 | info: 144 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 145 | @echo "Running Texinfo files through makeinfo..." 146 | make -C $(BUILDDIR)/texinfo info 147 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 148 | 149 | gettext: 150 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 151 | @echo 152 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 153 | 154 | changes: 155 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 156 | @echo 157 | @echo "The overview file is in $(BUILDDIR)/changes." 158 | 159 | linkcheck: 160 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 161 | @echo 162 | @echo "Link check complete; look for any errors in the above output " \ 163 | "or in $(BUILDDIR)/linkcheck/output.txt." 164 | 165 | doctest: 166 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 167 | @echo "Testing of doctests in the sources finished, look at the " \ 168 | "results in $(BUILDDIR)/doctest/output.txt." 169 | 170 | xml: 171 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 172 | @echo 173 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 174 | 175 | pseudoxml: 176 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 177 | @echo 178 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 179 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pyspectator.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pyspectator.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # pyspectator documentation build configuration file, created by 2 | # sphinx-quickstart on Tue Jul 15 09:34:46 2014. 3 | # 4 | # This file is execfile()d with the current directory set to its 5 | # containing dir. 6 | # 7 | # Note that not all possible configuration values are present in this 8 | # autogenerated file. 9 | # 10 | # All configuration values have a default; values that are commented out 11 | # serve to show the default. 12 | 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('../')) 16 | 17 | # -- General configuration ------------------------------------------------ 18 | 19 | # If your documentation needs a minimal Sphinx version, state it here. 20 | # needs_sphinx = '1.0' 21 | 22 | # Add any Sphinx extension module names here, as strings. They can be 23 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 24 | # ones. 25 | extensions = [ 26 | 'sphinx.ext.autodoc', 27 | 'sphinx.ext.napoleon', 28 | 'sphinx.ext.viewcode' 29 | ] 30 | 31 | # Add any paths that contain templates here, relative to this directory. 32 | templates_path = ['_templates'] 33 | 34 | # The suffix of source filenames. 35 | source_suffix = '.rst' 36 | 37 | # The encoding of source files. 38 | # source_encoding = 'utf-8-sig' 39 | 40 | # The master toctree document. 41 | master_doc = 'index' 42 | 43 | # General information about the project. 44 | project = 'pyspectator' 45 | copyright = '2014, uzumaxy' 46 | 47 | # The version info for the project you're documenting, acts as replacement for 48 | # |version| and |release|, also used in various other places throughout the 49 | # built documents. 50 | # 51 | # The short X.Y version. 52 | version = '1.0' 53 | # The full version, including alpha/beta/rc tags. 54 | release = '1.0.8' 55 | 56 | # The language for content autogenerated by Sphinx. Refer to documentation 57 | # for a list of supported languages. 58 | # language = None 59 | 60 | # There are two options for replacing |today|: either, you set today to some 61 | # non-false value, then it is used: 62 | # today = '' 63 | # Else, today_fmt is used as the format for a strftime call. 64 | # today_fmt = '%B %d, %Y' 65 | 66 | # List of patterns, relative to source directory, that match files and 67 | # directories to ignore when looking for source files. 68 | exclude_patterns = ['_build'] 69 | 70 | # The reST default role (used for this markup: `text`) to use for all 71 | # documents. 72 | # default_role = None 73 | 74 | # If true, '()' will be appended to :func: etc. cross-reference text. 75 | # add_function_parentheses = True 76 | 77 | # If true, the current module name will be prepended to all description 78 | # unit titles (such as .. function::). 79 | # add_module_names = True 80 | 81 | # If true, sectionauthor and moduleauthor directives will be shown in the 82 | # output. They are ignored by default. 83 | # show_authors = False 84 | 85 | # The name of the Pygments (syntax highlighting) style to use. 86 | pygments_style = 'sphinx' 87 | 88 | # A list of ignored prefixes for module index sorting. 89 | # modindex_common_prefix = [] 90 | 91 | # If true, keep warnings as "system message" paragraphs in the built documents. 92 | # keep_warnings = False 93 | 94 | 95 | # -- Options for HTML output ---------------------------------------------- 96 | 97 | # The theme to use for HTML and HTML Help pages. See the documentation for 98 | # a list of builtin themes. 99 | html_theme = 'default' 100 | 101 | # Theme options are theme-specific and customize the look and feel of a theme 102 | # further. For a list of options available for each theme, see the 103 | # documentation. 104 | # html_theme_options = {} 105 | 106 | # Add any paths that contain custom themes here, relative to this directory. 107 | # html_theme_path = [] 108 | 109 | # The name for this set of Sphinx documents. If None, it defaults to 110 | # " v documentation". 111 | # html_title = None 112 | 113 | # A shorter title for the navigation bar. Default is the same as html_title. 114 | # html_short_title = None 115 | 116 | # The name of an image file (relative to this directory) to place at the top 117 | # of the sidebar. 118 | # html_logo = None 119 | 120 | # The name of an image file (within the static path) to use as favicon of the 121 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 122 | # pixels large. 123 | html_favicon = '_static/favicon.ico' 124 | 125 | # Add any paths that contain custom static files (such as style sheets) here, 126 | # relative to this directory. They are copied after the builtin static files, 127 | # so a file named "default.css" will overwrite the builtin "default.css". 128 | html_static_path = ['_static'] 129 | 130 | # Add any extra paths that contain custom files (such as robots.txt or 131 | # .htaccess) here, relative to this directory. These files are copied 132 | # directly to the root of the documentation. 133 | # html_extra_path = [] 134 | 135 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 136 | # using the given strftime format. 137 | # html_last_updated_fmt = '%b %d, %Y' 138 | 139 | # If true, SmartyPants will be used to convert quotes and dashes to 140 | # typographically correct entities. 141 | # html_use_smartypants = True 142 | 143 | # Custom sidebar templates, maps document names to template names. 144 | # html_sidebars = {} 145 | 146 | # Additional templates that should be rendered to pages, maps page names to 147 | # template names. 148 | # html_additional_pages = {} 149 | 150 | # If false, no module index is generated. 151 | # html_domain_indices = True 152 | 153 | # If false, no index is generated. 154 | # html_use_index = True 155 | 156 | # If true, the index is split into individual pages for each letter. 157 | # html_split_index = False 158 | 159 | # If true, links to the reST sources are added to the pages. 160 | # html_show_sourcelink = True 161 | 162 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 163 | # html_show_sphinx = True 164 | 165 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 166 | # html_show_copyright = True 167 | 168 | # If true, an OpenSearch description file will be output, and all pages will 169 | # contain a tag referring to it. The value of this option must be the 170 | # base URL from which the finished HTML is served. 171 | # html_use_opensearch = '' 172 | 173 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 174 | # html_file_suffix = None 175 | 176 | # Output file base name for HTML help builder. 177 | htmlhelp_basename = 'pyspectatordoc' 178 | 179 | 180 | # -- Options for LaTeX output --------------------------------------------- 181 | 182 | latex_elements = { 183 | # The paper size ('letterpaper' or 'a4paper'). 184 | # 'papersize': 'letterpaper', 185 | 186 | # The font size ('10pt', '11pt' or '12pt'). 187 | # 'pointsize': '10pt', 188 | 189 | # Additional stuff for the LaTeX preamble. 190 | # 'preamble': '', 191 | } 192 | 193 | # Grouping the document tree into LaTeX files. List of tuples 194 | # (source start file, target name, title, 195 | # author, documentclass [howto, manual, or own class]). 196 | latex_documents = [( 197 | 'index', 'pyspectator.tex', 'pyspectator Documentation', 'uzumaxy', 198 | 'manual' 199 | ), ] 200 | 201 | # The name of an image file (relative to this directory) to place at the top of 202 | # the title page. 203 | # latex_logo = None 204 | 205 | # For "manual" documents, if this is true, then toplevel headings are parts, 206 | # not chapters. 207 | # latex_use_parts = False 208 | 209 | # If true, show page references after internal links. 210 | # latex_show_pagerefs = False 211 | 212 | # If true, show URL addresses after external links. 213 | # latex_show_urls = False 214 | 215 | # Documents to append as an appendix to all manuals. 216 | # latex_appendices = [] 217 | 218 | # If false, no module index is generated. 219 | # latex_domain_indices = True 220 | 221 | 222 | # -- Options for manual page output --------------------------------------- 223 | 224 | # One entry per manual page. List of tuples 225 | # (source start file, name, description, authors, manual section). 226 | man_pages = [ 227 | ('index', 'pyspectator', 'pyspectator Documentation', 228 | ['uzumaxy'], 1) 229 | ] 230 | 231 | # If true, show URL addresses after external links. 232 | # man_show_urls = False 233 | 234 | 235 | # -- Options for Texinfo output ------------------------------------------- 236 | 237 | # Grouping the document tree into Texinfo files. List of tuples 238 | # (source start file, target name, title, author, 239 | # dir menu entry, description, category) 240 | texinfo_documents = [( 241 | 'index', 'pyspectator', 'pyspectator Documentation', 'uzumaxy', 242 | 'pyspectator', 'One line description of project.', 'Miscellaneous' 243 | ), ] 244 | 245 | # Documents to append as an appendix to all manuals. 246 | # texinfo_appendices = [] 247 | 248 | # If false, no module index is generated. 249 | # texinfo_domain_indices = True 250 | 251 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 252 | # texinfo_show_urls = 'footnote' 253 | 254 | # If true, do not generate a @detailmenu in the "Top" node's menu. 255 | # texinfo_no_detailmenu = False 256 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # A comma-separated list of package or module names from where C extensions may 4 | # be loaded. Extensions are loading into the active Python interpreter and may 5 | # run arbitrary code 6 | extension-pkg-whitelist= 7 | 8 | # Add files or directories to the blacklist. They should be base names, not 9 | # paths. 10 | ignore=CVS .git 11 | 12 | # Add files or directories matching the regex patterns to the blacklist. The 13 | # regex matches against base names, not paths. 14 | ignore-patterns= 15 | 16 | # Python code to execute, usually for sys.path manipulation such as 17 | # pygtk.require(). 18 | #init-hook= 19 | 20 | # Use multiple processes to speed up Pylint. 21 | jobs=1 22 | 23 | # List of plugins (as comma separated values of python modules names) to load, 24 | # usually to register additional checkers. 25 | load-plugins= 26 | 27 | # Pickle collected data for later comparisons. 28 | persistent=yes 29 | 30 | # Specify a configuration file. 31 | #rcfile= 32 | 33 | # When enabled, pylint would attempt to guess common misconfiguration and emit 34 | # user-friendly hints instead of false-positive error messages 35 | suggestion-mode=yes 36 | 37 | # Allow loading of arbitrary C extensions. Extensions are imported into the 38 | # active Python interpreter and may run arbitrary code. 39 | unsafe-load-any-extension=no 40 | 41 | 42 | [MESSAGES CONTROL] 43 | 44 | # Only show warnings with the listed confidence levels. Leave empty to show 45 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED 46 | confidence= 47 | 48 | # Disable the message, report, category or checker with the given id(s). You 49 | # can either give multiple identifiers separated by comma (,) or put this 50 | # option multiple times (only on the command line, not in the configuration 51 | # file where it should appear only once).You can also use "--disable=all" to 52 | # disable everything first and then reenable specific checks. For example, if 53 | # you want to run only the similarities checker, you can use "--disable=all 54 | # --enable=similarities". If you want to run only the classes checker, but have 55 | # no Warning level messages displayed, use"--disable=all --enable=classes 56 | # --disable=W" 57 | disable=print-statement, 58 | parameter-unpacking, 59 | unpacking-in-except, 60 | old-raise-syntax, 61 | backtick, 62 | long-suffix, 63 | old-ne-operator, 64 | old-octal-literal, 65 | import-star-module-level, 66 | non-ascii-bytes-literal, 67 | raw-checker-failed, 68 | bad-inline-option, 69 | locally-disabled, 70 | locally-enabled, 71 | file-ignored, 72 | suppressed-message, 73 | useless-suppression, 74 | deprecated-pragma, 75 | apply-builtin, 76 | basestring-builtin, 77 | buffer-builtin, 78 | cmp-builtin, 79 | coerce-builtin, 80 | execfile-builtin, 81 | file-builtin, 82 | long-builtin, 83 | raw_input-builtin, 84 | reduce-builtin, 85 | standarderror-builtin, 86 | unicode-builtin, 87 | xrange-builtin, 88 | coerce-method, 89 | delslice-method, 90 | getslice-method, 91 | setslice-method, 92 | no-absolute-import, 93 | old-division, 94 | dict-iter-method, 95 | dict-view-method, 96 | next-method-called, 97 | metaclass-assignment, 98 | indexing-exception, 99 | raising-string, 100 | reload-builtin, 101 | oct-method, 102 | hex-method, 103 | nonzero-method, 104 | cmp-method, 105 | input-builtin, 106 | round-builtin, 107 | intern-builtin, 108 | unichr-builtin, 109 | map-builtin-not-iterating, 110 | zip-builtin-not-iterating, 111 | range-builtin-not-iterating, 112 | filter-builtin-not-iterating, 113 | using-cmp-argument, 114 | eq-without-hash, 115 | div-method, 116 | idiv-method, 117 | rdiv-method, 118 | exception-message-attribute, 119 | invalid-str-codec, 120 | sys-max-int, 121 | bad-python3-import, 122 | deprecated-string-function, 123 | deprecated-str-translate-call, 124 | deprecated-itertools-function, 125 | deprecated-types-field, 126 | next-method-defined, 127 | dict-items-not-iterating, 128 | dict-keys-not-iterating, 129 | dict-values-not-iterating, 130 | C0111, 131 | I1101 132 | 133 | # Enable the message, report, category or checker with the given id(s). You can 134 | # either give multiple identifier separated by comma (,) or put this option 135 | # multiple time (only on the command line, not in the configuration file where 136 | # it should appear only once). See also the "--disable" option for examples. 137 | enable=c-extension-no-member 138 | 139 | 140 | [REPORTS] 141 | 142 | # Python expression which should return a note less than 10 (10 is the highest 143 | # note). You have access to the variables errors warning, statement which 144 | # respectively contain the number of errors / warnings messages and the total 145 | # number of statements analyzed. This is used by the global evaluation report 146 | # (RP0004). 147 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 148 | 149 | # Template used to display messages. This is a python new-style format string 150 | # used to format the message information. See doc for all details 151 | #msg-template= 152 | 153 | # Set the output format. Available formats are text, parseable, colorized, json 154 | # and msvs (visual studio).You can also give a reporter class, eg 155 | # mypackage.mymodule.MyReporterClass. 156 | output-format=text 157 | 158 | # Tells whether to display a full report or only the messages 159 | reports=no 160 | 161 | # Activate the evaluation score. 162 | score=yes 163 | 164 | 165 | [REFACTORING] 166 | 167 | # Maximum number of nested blocks for function / method body 168 | max-nested-blocks=5 169 | 170 | 171 | [LOGGING] 172 | 173 | # Logging modules to check that the string format arguments are in logging 174 | # function parameter format 175 | logging-modules=logging 176 | 177 | 178 | [SPELLING] 179 | 180 | # Limits count of emitted suggestions for spelling mistakes 181 | max-spelling-suggestions=4 182 | 183 | # Spelling dictionary name. Available dictionaries: none. To make it working 184 | # install python-enchant package. 185 | spelling-dict= 186 | 187 | # List of comma separated words that should not be checked. 188 | spelling-ignore-words= 189 | 190 | # A path to a file that contains private dictionary; one word per line. 191 | spelling-private-dict-file= 192 | 193 | # Tells whether to store unknown words to indicated private dictionary in 194 | # --spelling-private-dict-file option instead of raising a message. 195 | spelling-store-unknown-words=no 196 | 197 | 198 | [MISCELLANEOUS] 199 | 200 | # List of note tags to take in consideration, separated by a comma. 201 | notes=FIXME, 202 | XXX, 203 | TODO 204 | 205 | 206 | [TYPECHECK] 207 | 208 | # List of decorators that produce context managers, such as 209 | # contextlib.contextmanager. Add to this list to register other decorators that 210 | # produce valid context managers. 211 | contextmanager-decorators=contextlib.contextmanager 212 | 213 | # List of members which are set dynamically and missed by pylint inference 214 | # system, and so shouldn't trigger E1101 when accessed. Python regular 215 | # expressions are accepted. 216 | generated-members= 217 | 218 | # Tells whether missing members accessed in mixin class should be ignored. A 219 | # mixin class is detected if its name ends with "mixin" (case insensitive). 220 | ignore-mixin-members=yes 221 | 222 | # This flag controls whether pylint should warn about no-member and similar 223 | # checks whenever an opaque object is returned when inferring. The inference 224 | # can return multiple potential results while evaluating a Python object, but 225 | # some branches might not be evaluated, which results in partial inference. In 226 | # that case, it might be useful to still emit no-member and other checks for 227 | # the rest of the inferred objects. 228 | ignore-on-opaque-inference=yes 229 | 230 | # List of class names for which member attributes should not be checked (useful 231 | # for classes with dynamically set attributes). This supports the use of 232 | # qualified names. 233 | ignored-classes=optparse.Values,thread._local,_thread._local 234 | 235 | # List of module names for which member attributes should not be checked 236 | # (useful for modules/projects where namespaces are manipulated during runtime 237 | # and thus existing member attributes cannot be deduced by static analysis. It 238 | # supports qualified module names, as well as Unix pattern matching. 239 | ignored-modules= 240 | 241 | # Show a hint with possible names when a member name was not found. The aspect 242 | # of finding the hint is based on edit distance. 243 | missing-member-hint=yes 244 | 245 | # The minimum edit distance a name should have in order to be considered a 246 | # similar match for a missing member name. 247 | missing-member-hint-distance=1 248 | 249 | # The total number of similar names that should be taken in consideration when 250 | # showing a hint for a missing member. 251 | missing-member-max-choices=1 252 | 253 | 254 | [VARIABLES] 255 | 256 | # List of additional names supposed to be defined in builtins. Remember that 257 | # you should avoid to define new builtins when possible. 258 | additional-builtins= 259 | 260 | # Tells whether unused global variables should be treated as a violation. 261 | allow-global-unused-variables=yes 262 | 263 | # List of strings which can identify a callback function by name. A callback 264 | # name must start or end with one of those strings. 265 | callbacks=cb_, 266 | _cb 267 | 268 | # A regular expression matching the name of dummy variables (i.e. expectedly 269 | # not used). 270 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ 271 | 272 | # Argument names that match this expression will be ignored. Default to name 273 | # with leading underscore 274 | ignored-argument-names=_.*|^ignored_|^unused_ 275 | 276 | # Tells whether we should check for unused import in __init__ files. 277 | init-import=no 278 | 279 | # List of qualified module names which can have objects that can redefine 280 | # builtins. 281 | redefining-builtins-modules=six.moves,past.builtins,future.builtins 282 | 283 | 284 | [FORMAT] 285 | 286 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 287 | expected-line-ending-format= 288 | 289 | # Regexp for a line that is allowed to be longer than the limit. 290 | ignore-long-lines=^\s*(# )??$ 291 | 292 | # Number of spaces of indent required inside a hanging or continued line. 293 | indent-after-paren=4 294 | 295 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 296 | # tab). 297 | indent-string=' ' 298 | 299 | # Maximum number of characters on a single line. 300 | max-line-length=100 301 | 302 | # Maximum number of lines in a module 303 | max-module-lines=1000 304 | 305 | # List of optional constructs for which whitespace checking is disabled. `dict- 306 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. 307 | # `trailing-comma` allows a space between comma and closing bracket: (a, ). 308 | # `empty-line` allows space-only lines. 309 | no-space-check=trailing-comma, 310 | dict-separator 311 | 312 | # Allow the body of a class to be on the same line as the declaration if body 313 | # contains single statement. 314 | single-line-class-stmt=no 315 | 316 | # Allow the body of an if to be on the same line as the test if there is no 317 | # else. 318 | single-line-if-stmt=no 319 | 320 | 321 | [SIMILARITIES] 322 | 323 | # Ignore comments when computing similarities. 324 | ignore-comments=yes 325 | 326 | # Ignore docstrings when computing similarities. 327 | ignore-docstrings=yes 328 | 329 | # Ignore imports when computing similarities. 330 | ignore-imports=no 331 | 332 | # Minimum lines number of a similarity. 333 | min-similarity-lines=4 334 | 335 | 336 | [BASIC] 337 | 338 | # Naming style matching correct argument names 339 | argument-naming-style=snake_case 340 | 341 | # Regular expression matching correct argument names. Overrides argument- 342 | # naming-style 343 | #argument-rgx= 344 | 345 | # Naming style matching correct attribute names 346 | attr-naming-style=snake_case 347 | 348 | # Regular expression matching correct attribute names. Overrides attr-naming- 349 | # style 350 | #attr-rgx= 351 | 352 | # Bad variable names which should always be refused, separated by a comma 353 | bad-names=foo, 354 | bar, 355 | baz, 356 | toto, 357 | tutu, 358 | tata 359 | 360 | # Naming style matching correct class attribute names 361 | class-attribute-naming-style=any 362 | 363 | # Regular expression matching correct class attribute names. Overrides class- 364 | # attribute-naming-style 365 | #class-attribute-rgx= 366 | 367 | # Naming style matching correct class names 368 | class-naming-style=PascalCase 369 | 370 | # Regular expression matching correct class names. Overrides class-naming-style 371 | #class-rgx= 372 | 373 | # Naming style matching correct constant names 374 | const-naming-style=UPPER_CASE 375 | 376 | # Regular expression matching correct constant names. Overrides const-naming- 377 | # style 378 | #const-rgx= 379 | 380 | # Minimum line length for functions/classes that require docstrings, shorter 381 | # ones are exempt. 382 | docstring-min-length=-1 383 | 384 | # Naming style matching correct function names 385 | function-naming-style=snake_case 386 | 387 | # Regular expression matching correct function names. Overrides function- 388 | # naming-style 389 | #function-rgx= 390 | 391 | # Good variable names which should always be accepted, separated by a comma 392 | good-names=i, 393 | j, 394 | k, 395 | ex, 396 | Run, 397 | _ 398 | 399 | # Include a hint for the correct naming format with invalid-name 400 | include-naming-hint=no 401 | 402 | # Naming style matching correct inline iteration names 403 | inlinevar-naming-style=any 404 | 405 | # Regular expression matching correct inline iteration names. Overrides 406 | # inlinevar-naming-style 407 | #inlinevar-rgx= 408 | 409 | # Naming style matching correct method names 410 | method-naming-style=snake_case 411 | 412 | # Regular expression matching correct method names. Overrides method-naming- 413 | # style 414 | #method-rgx= 415 | 416 | # Naming style matching correct module names 417 | module-naming-style=snake_case 418 | 419 | # Regular expression matching correct module names. Overrides module-naming- 420 | # style 421 | #module-rgx= 422 | 423 | # Colon-delimited sets of names that determine each other's naming style when 424 | # the name regexes allow several styles. 425 | name-group= 426 | 427 | # Regular expression which should only match function or class names that do 428 | # not require a docstring. 429 | no-docstring-rgx=^_ 430 | 431 | # List of decorators that produce properties, such as abc.abstractproperty. Add 432 | # to this list to register other decorators that produce valid properties. 433 | property-classes=abc.abstractproperty 434 | 435 | # Naming style matching correct variable names 436 | variable-naming-style=snake_case 437 | 438 | # Regular expression matching correct variable names. Overrides variable- 439 | # naming-style 440 | #variable-rgx= 441 | 442 | 443 | [IMPORTS] 444 | 445 | # Allow wildcard imports from modules that define __all__. 446 | allow-wildcard-with-all=no 447 | 448 | # Analyse import fallback blocks. This can be used to support both Python 2 and 449 | # 3 compatible code, which means that the block might have code that exists 450 | # only in one or another interpreter, leading to false positives when analysed. 451 | analyse-fallback-blocks=no 452 | 453 | # Deprecated modules which should not be used, separated by a comma 454 | deprecated-modules=optparse,tkinter.tix 455 | 456 | # Create a graph of external dependencies in the given file (report RP0402 must 457 | # not be disabled) 458 | ext-import-graph= 459 | 460 | # Create a graph of every (i.e. internal and external) dependencies in the 461 | # given file (report RP0402 must not be disabled) 462 | import-graph= 463 | 464 | # Create a graph of internal dependencies in the given file (report RP0402 must 465 | # not be disabled) 466 | int-import-graph= 467 | 468 | # Force import order to recognize a module as part of the standard 469 | # compatibility libraries. 470 | known-standard-library= 471 | 472 | # Force import order to recognize a module as part of a third party library. 473 | known-third-party=enchant 474 | 475 | 476 | [CLASSES] 477 | 478 | # List of method names used to declare (i.e. assign) instance attributes. 479 | defining-attr-methods=__init__, 480 | __new__, 481 | setUp 482 | 483 | # List of member names, which should be excluded from the protected access 484 | # warning. 485 | exclude-protected=_asdict, 486 | _fields, 487 | _replace, 488 | _source, 489 | _make 490 | 491 | # List of valid names for the first argument in a class method. 492 | valid-classmethod-first-arg=cls 493 | 494 | # List of valid names for the first argument in a metaclass class method. 495 | valid-metaclass-classmethod-first-arg=mcs 496 | 497 | 498 | [DESIGN] 499 | 500 | # Maximum number of arguments for function / method 501 | max-args=5 502 | 503 | # Maximum number of attributes for a class (see R0902). 504 | max-attributes=7 505 | 506 | # Maximum number of boolean expressions in a if statement 507 | max-bool-expr=5 508 | 509 | # Maximum number of branch for function / method body 510 | max-branches=12 511 | 512 | # Maximum number of locals for function / method body 513 | max-locals=15 514 | 515 | # Maximum number of parents for a class (see R0901). 516 | max-parents=7 517 | 518 | # Maximum number of public methods for a class (see R0904). 519 | max-public-methods=20 520 | 521 | # Maximum number of return / yield for function / method body 522 | max-returns=6 523 | 524 | # Maximum number of statements in function / method body 525 | max-statements=50 526 | 527 | # Minimum number of public methods for a class (see R0903). 528 | min-public-methods=2 529 | 530 | 531 | [EXCEPTIONS] 532 | 533 | # Exceptions that will emit a warning when being caught. Defaults to 534 | # "Exception" 535 | overgeneral-exceptions=Exception 536 | --------------------------------------------------------------------------------