-
-
Notifications
You must be signed in to change notification settings - Fork 37
Info for contributors
Currently, Archey is written as a root Python package archey
with modules for our core functionality:
-
api.py
provides the JSON API, which may be extended in the future to support other notations. -
colors.py
provides functionality dealing with ANSI/ECMA escape codes for coloured text. -
configuration.py
provides a singletonConfiguration
class, which is hopefully self-explanatory, as long as default required options. -
distributions.py
contains the supported distributions and methods for detecting the system one. -
entry.py
is a base-class definition which is used by all of Archey's entries; more details below. -
environment.py
contains a singleton class which is our interface to deal with "global" environment variables altering Archey's behavior. -
output.py
has theOutput
class, which deals with all of Archey's output tasks. -
processes.py
contains a singleton class which gathers a list of all running processes on the system. -
screenshot.py
contains a standalone function which is responsible to find a way to take a screenshot ("best effort"). -
singleton.py
contains the singleton meta-class used byProcesses
,Configuration
,Environment
&Utility
. -
utility.py
contains a singleton class defining some internal utility functions used by Archey.
There are also sub-packages:
-
archey/entries
-- Each module in this package corresponds to one Archey entry. -
archey/logos
-- Each module in this package contains a distribution's logo.
A brief overview of Archey's directory structure is:
.
├── .github/ // Project meta files related to GitHub repository
├── archey/ // Python module root directory
│ ├── entries/ // Code for each entry
│ ├── logos/ // ASCII art logos and colors, as Python modules
│ ├── test/ // Unit tests
│ ├── py.typed // PEP-561 compliance file
│ └── *.py // Entry points and main Python modules
├── dist/ // Packages and binaries generation target
├── packaging/ // Build scripts for packaging
├── pyproject.toml // Project tools configuration file (PEP-518)
├── CHANGELOG.md // Changelog info
├── COPYRIGHT.md // Copyright info
├── LICENSE // Project licensing
├── README.md // Project description and documentation
├── archey.1 // *NIX manual page
├── config.json // Default configuration file
└── setup.py // Distutils packaging file
Some useful things to know while writing code for Archey...
If you're writing an entry, inheriting from the archey.entry.Entry
class will provide you with configuration in the instance attribute options
.
from archey.entry import Entry
class MyEntry(Entry):
# Use this internal attribute if your entry should have a "pretty name" different than the class'.
_PRETTY_NAME = 'My Entry'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# `self.options` contains specific configuration related to your entry.
an_option_value = self.options.get('key')
# For i18n, `default_strings` will also be propagated as a protected attribute.
not_detected_str = self._default_strings.get('not_detected')
# Starting with Archey >= 4.13.0, you may use a dedicated logger.
self._logger.warning('This is a warning message.')
Otherwise, when writing/fixing an internal module of Archey, to get the (global) configuration set by the user, import the configuration module and simply instantiate the Configuration
class:
from archey.configuration import Configuration
config = Configuration()
some_config_item = config.get('key')
This works at all times in all modules, since Configuration
is a singleton which is populated when Archey launches.
Configuration
is also an iterable, so you can get the whole thing as a dict
if you really want:
from archey.configuration import Configuration
config_dict = dict(Configuration())
The Entry
base-class (seen in archey/entry.py
) paints the basic picture of what an entry is. The simplest possible entry you could write is the following:
from archey.entry import Entry
class MyEntry(Entry):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# `name` defaults to entry's internal name.
self.name = 'MyEntry'
self.value = None
In an entry, the goal is to put a Python object into the value
attribute which best represents the data you have. For example, the Hostname
entry's value
is simply a string containing your system host-name in it. A slightly more complex example is Distro
, whose value
is a dictionary with the keys name
and arch
, whose values are strings corresponding to the name and architecture of the detected distribution respectively.
When Archey is run, all entries are instantiated and either:
- If running in normal mode,
Output
callsMyEntry.output
to add the entry to the output. - If running in API mode (i.e. currently JSON output mode using
-j
),output
is never called and thevalue
attribute is serialized to JSON using Python's default serializer.
The default Entry
base-class output
method simply calls str()
on value
to get a string representation -- this method calls the __str__
method, falling back to repr()
. If you want, for example, to output a dictionary with custom formatting, you have to override output
. You should be able to do this easily by expanding on the basic method in the Entry
base class.
Keep in mind:
- Don't put important code in the
output
method that is required for a sanevalue
attribute. - Don't put a custom class in
value
, otherwise we can't serialize it for JSON output!
Archey uses the unittest
Python module. All of our tests can be found in archey/test
. Each file is named in the format test_archey_{module name}
. All entry tests belong in the entries
sub-folder.
There is currently one helper class for all other modules; this is the CustomAssertions
class (it can also be used in entry tests if desired). It is used by inheriting it in the testing class, e.g.:
import unittest
from archey.test import CustomAssertions
class TestMyModule(unittest.TestCase, CustomAssertions):
# Custom assertions are now available in all tests in this class.
# Call them the same way as `unittest`'s assertions.
# e.g:
def test_some_method(self):
self.assertListEmpty(MyModule.empty_list_attribute)
The list of custom assertions is:
-
assertListEmpty(obj)
- asserts that the supplied object:- is a list -
isinstance(obj, list) == True
- contains no items -
(not obj) == True
- is a list -
There are some supplied helper methods in archey/test/entries/__init__.py
to aid writing clean and stable entry tests. To use them, simply import them, e.g.:
from archey.test.entries import HelperMethods
Use to get a mock "instance" of an entry, e.g.:
CPU_mock_instance = HelperMethods.entry_mock(CPU)
This method is intended to aid in writing tests for instance methods of an entry. It creates a MagicMock
which wraps all attributes of the entry, and acts like a "default" entry which inherits from archey.entry.Entry
. That is to say, it always additionally has:
-
.name
attribute equal to the class-name of the entry supplied. -
.value
attribute asNone
. -
.options
attribute - see below. -
._default_strings
protected attribute, containing default i18n strings. -
._logger
protected attribute, a dedicatedlogging.Logger
object (Archey >= 4.13.0)
Sure, you might :
- propose documentation fixes or improvements for internal doc-strings, manual page, README or even this very Wiki ;
- discuss changes or new features regarding the future (roadmap) ;
- consider sponsoring the maintainer.