Skip to content

Commit c84481b

Browse files
committed
improve property base doc
1 parent 70d6e63 commit c84481b

File tree

6 files changed

+242
-249
lines changed

6 files changed

+242
-249
lines changed
Lines changed: 63 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,152 @@
1-
# Common arguments to all properties
1+
# Common arguments to all properties
22

33
[API Reference](../../api-reference/property)
44

5+
### `allow_None`, `constant` & `readonly`
56

6-
### `allow_None`, `constant` & `readonly`
7-
8-
* if `allow_None` is `True`, property supports `None` apart from its own type
9-
* `readonly` (being `True`) makes the property read-only or execute the getter method
10-
* `constant` (being `True`), again makes the property read-only but can be set once if `allow_None` is `True`.
7+
- if `allow_None` is `True`, property supports `None` apart from its own type
8+
- `readonly` (being `True`) makes the property read-only or execute the getter method
9+
- `constant` (being `True`), again makes the property read-only but can be set once if `allow_None` is `True`.
1110
This is useful to set the property once at `__init__()` but remain constant after that.
1211

1312
```py title="allow None, constant and readonly" linenums="1" hl_lines="7 15 19"
14-
--8<-- "docs/howto/code/properties/common_args_1.py:1:24"
13+
--8<-- "docs/beginners-guide/code/properties/common_args_1.py:1:24"
1514
```
1615

1716
=== "`allow_None=True`"
1817

1918
```py title="allow None, constant and readonly" linenums="1"
20-
--8<-- "docs/howto/code/properties/common_args_1.py:26:28"
19+
--8<-- "docs/beginners-guide/code/properties/common_args_1.py:26:28"
2120
```
2221

2322
=== "`allow_None=False`"
2423

2524
```py title="allow None, constant and readonly" linenums="1"
26-
--8<-- "docs/howto/code/properties/common_args_1.py:31:32"
25+
--8<-- "docs/beginners-guide/code/properties/common_args_1.py:31:32"
2726
```
2827

2928
=== "`readonly=True`"
3029

3130
```py title="allow None, constant and readonly" linenums="1"
32-
--8<-- "docs/howto/code/properties/common_args_1.py:35:35"
31+
--8<-- "docs/beginners-guide/code/properties/common_args_1.py:35:35"
3332
```
3433

3534
=== "`constant=True`"
3635

3736
```py title="allow None, constant and readonly" linenums="1"
38-
--8<-- "docs/howto/code/properties/common_args_1.py:38:40"
37+
--8<-- "docs/beginners-guide/code/properties/common_args_1.py:38:40"
3938
```
4039

41-
4240
### `doc` and `label`
4341

44-
`doc` allows clients to fetch a docstring for the property. `label` can be used to show the property
45-
in a GUI for example.
42+
`doc` allows clients to fetch a docstring for the property. `label` can be used to show the property
43+
in a GUI for example.
4644

4745
```py title="allow None, constant and readonly" linenums="1" hl_lines="8-9"
48-
--8<-- "docs/howto/code/properties/common_args_1.py:1:6"
49-
--8<-- "docs/howto/code/properties/common_args_1.py:11:14"
46+
--8<-- "docs/beginners-guide/code/properties/common_args_1.py:1:6"
47+
--8<-- "docs/beginners-guide/code/properties/common_args_1.py:11:14"
5048
```
5149

52-
5350
### `default`, `fget`, `fset` & `fdel`
5451

55-
To provide a getter-setter (& deleter) method is optional. If none given, when the property is set/written, the value
56-
is stored inside the instance's `__dict__` under the name `<given property name >_param_value`
57-
(for example, `serial_number_param_value` for `serial_number`). In layman's terms,
58-
`__dict__` is the internal map where the attributes of the object are stored by python.
52+
To provide a getter-setter (& deleter) method is optional. If none given, when the property is set/written, the value
53+
is stored inside the instance's `__dict__` under the name `<given property name >_param_value`
54+
(for example, `serial_number_param_value` for `serial_number`). In layman's terms,
55+
`__dict__` is the internal map where the attributes of the object are stored by python.
5956

60-
When a value assignment was never called on the property, `default` is returned when reading the value. This is the purpose of the `default` argument. If a setter/deleter is given, getter is mandatory. In this case, `default` is also ignored & the getter is always executed.
57+
When a value assignment was never called on the property, `default` is returned when reading the value. This is the purpose of the `default` argument. If a setter/deleter is given, getter is mandatory. In this case, `default` is also ignored & the getter is always executed.
6158

6259
=== "with decorator"
6360

64-
```py linenums="1"
65-
--8<-- "docs/howto/code/properties/common_args_2.py:22:42"
66-
--8<-- "docs/howto/code/properties/common_args_2.py:46:48"
67-
--8<-- "docs/howto/code/properties/common_args_2.py:98:102"
61+
```py linenums="1"
62+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:22:42"
63+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:46:48"
64+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:98:102"
6865
```
66+
6967
=== "with fget-fset-fdel arguments"
7068

71-
```py linenums="1"
72-
--8<-- "docs/howto/code/properties/common_args_2.py:22:24"
73-
--8<-- "docs/howto/code/properties/common_args_2.py:29:34"
74-
--8<-- "docs/howto/code/properties/common_args_2.py:36:48"
75-
--8<-- "docs/howto/code/properties/common_args_2.py:98:102"
69+
```py linenums="1"
70+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:22:24"
71+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:29:34"
72+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:36:48"
73+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:98:102"
7674
```
7775

78-
If default is desirable, one has to return it manually in the getter method by accessing the property [descriptor object directly](../#__codelineno-2-15).
79-
76+
If default is desirable, one has to return it manually in the getter method by accessing the property [descriptor object directly](../#__codelineno-2-15).
8077

8178
### `class_member`
8279

83-
If `class_member` is True, the value is set in the class' `__dict__` (i.e. becomes a class attribute)
84-
instead of instance's `__dict__` (instance's attribute).
85-
Custom getter-setter-deleter are not compatible with this option currently. `class_member` takes precedence over fget-fset-fdel,
80+
If `class_member` is True, the value is set in the class' `__dict__` (i.e. becomes a class attribute)
81+
instead of instance's `__dict__` (instance's attribute).
82+
Custom getter-setter-deleter are not compatible with this option currently. `class_member` takes precedence over fget-fset-fdel,
8683
which in turn has precedence over `default`.
8784

8885
```py title="class member" linenums="1" hl_lines="21-22"
89-
--8<-- "docs/howto/code/properties/common_args_2.py:7:20"
90-
--8<-- "docs/howto/code/properties/common_args_2.py:22:24"
91-
--8<-- "docs/howto/code/properties/common_args_2.py:51:57"
92-
--8<-- "docs/howto/code/properties/common_args_2.py:98:100"
93-
--8<-- "docs/howto/code/properties/common_args_2.py:103:106"
86+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:7:20"
87+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:22:24"
88+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:51:57"
89+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:98:100"
90+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:103:106"
9491
```
9592

96-
`class_member` can still be used with a default value if there is no custom fget-fset-fdel.
97-
93+
`class_member` can still be used with a default value if there is no custom fget-fset-fdel.
9894

9995
### `remote`
10096

10197
setting `remote` to False makes the inaccessible to a client but accessible to the object locally. This is still useful to type-restrict python attributes to provide an interface to other developers using your class, for example, when someone else inherits your `Thing`. For example, the `Thing`'s `logger` is implemented in this fashion:
10298

10399
```py title="local properties" linenums="1" hl_lines="8"
104-
import logging
100+
import logging
105101
from hololinked.server.properties import ClassSelector
106102

107103
class Thing:
108104
"""Subclass from here to expose hardware or python objects on the network"""
109-
105+
110106
logger = ClassSelector(class_=logging.Logger, default=None, allow_None=True,
111107
remote=False,
112-
doc="""logging.Logger instance to print log messages.
113-
Default logger with a IO-stream handler and network
108+
doc="""logging.Logger instance to print log messages.
109+
Default logger with a IO-stream handler and network
114110
accessible handler is created if none supplied."""
115111
) # type: logging.Logger
116112
```
117113

118-
119114
### `state`
120115

121-
When `state` is specifed, the property is writeable only when the `Thing`'s `StateMachine` is in that specified state (or
122-
in the list of allowed states):
116+
When `state` is specifed, the property is writeable only when the `Thing`'s `StateMachine` is in that specified state (or
117+
in the list of allowed states):
123118

124-
```py title="state machine state" linenums="1" hl_lines="17"
125-
--8<-- "docs/howto/code/properties/common_args_2.py:22:24"
126-
--8<-- "docs/howto/code/properties/common_args_2.py:60:76"
119+
```py title="state machine state" linenums="1" hl_lines="17"
120+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:22:24"
121+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:60:76"
127122
```
128123

129-
This is also currently applicable only when set operations are called by clients. Local set operations are always executed irrespective of the state machine state. A get operation is always executed as well even from the clients irrespective of the state.
124+
This is also currently applicable only when set operations are called by clients. Local set operations are always executed irrespective of the state machine state. A get operation is always executed as well even from the clients irrespective of the state.
130125

131-
`observable`
132-
------------
126+
## `observable`
133127

134128
Observable properties push change events when the property is set or read. This is useful when one wants to monitor the
135-
property for changes without polling from the client. The payload of the change event is the new value of the property.
129+
property for changes without polling from the client. The payload of the change event is the new value of the property.
136130

137-
```py title="state machine state" linenums="1" hl_lines="19"
138-
--8<-- "docs/howto/code/properties/common_args_2.py:22:24"
139-
--8<-- "docs/howto/code/properties/common_args_2.py:79:95"
131+
```py title="state machine state" linenums="1" hl_lines="19"
132+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:22:24"
133+
--8<-- "docs/beginners-guide/code/properties/common_args_2.py:79:95"
140134
```
141135

142-
`metadata`
143-
----------
136+
## `metadata`
144137

145-
`metadata` is a dictionary that allows storing arbitrary metadata about the property. For example, one can store units of the physical
146-
quantity.
138+
`metadata` is a dictionary that allows storing arbitrary metadata about the property. For example, one can store units of the physical
139+
quantity.
147140

148-
`db_init`, `db_commit` & `db_persist`
149-
-------------------------------------
141+
## `db_init`, `db_commit` & `db_persist`
150142

151-
Properties can be stored in a file or a database and loaded from them when the `Thing` is stopped and restarted. This is useful especially to preserve the settings of the hardware when the server undergoes a restart, either through system restart or any other reason.
143+
Properties can be stored in a file or a database and loaded from them when the `Thing` is stopped and restarted. This is useful especially to preserve the settings of the hardware when the server undergoes a restart, either through system restart or any other reason.
152144

153-
* `db_init` only loads a property from database, when the value is changed, its not written back to the database.
145+
- `db_init` only loads a property from database, when the value is changed, its not written back to the database.
154146
For this option, the value has to be pre-created in the database in some other fashion.
155147

156-
* `db_commit` only writes the value into the database when an assignment is called.
157-
158-
* `db_persist` both stores and loads the property from the database.
148+
- `db_commit` only writes the value into the database when an assignment is called.
159149

160-
Supported databases are MySQL, Postgres & SQLite currently. Look at database how-to for supply database configuration.
150+
- `db_persist` both stores and loads the property from the database.
161151

152+
Supported databases are MySQL, Postgres & SQLite currently. Look at database how-to for supply database configuration.
Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,54 @@
11
# Extending
22

3-
Properties can also be extended to define custom types, validation and coercion based on specific requirements. As a contrived example, one may define a JPEG image attribute which may accept a numpy array as input, have a compression level setting, transpose and flip the image if necessary.
3+
Properties can also be extended to define custom types, validation and coercion based on specific requirements. As a contrived example, one may define a JPEG image attribute which may accept a numpy array as input, have a compression level setting, transpose and flip the image if necessary.
44

55
To create the property, inherit from the `Property` object and define the `__init__`:
66

7-
```py title='Subclassing Property' linenums="1"
8-
--8<-- "docs/howto/code/properties/extending.py:2:2"
9-
--8<-- "docs/howto/code/properties/extending.py:4:20"
7+
```py title='Subclassing Property' linenums="1"
8+
--8<-- "docs/beginners-guide/code/properties/extending.py:2:2"
9+
--8<-- "docs/beginners-guide/code/properties/extending.py:4:20"
1010
```
1111

1212
It is possible to use the `__set__()` to carry out type validation & coercion:
1313

1414
```py title='Validation with __set__()' linenums="1"
15-
--8<-- "docs/howto/code/properties/extending.py:1:7"
16-
--8<-- "docs/howto/code/properties/extending.py:39:58"
15+
--8<-- "docs/beginners-guide/code/properties/extending.py:1:7"
16+
--8<-- "docs/beginners-guide/code/properties/extending.py:39:58"
1717
```
1818

19-
Basically, check the types, manipulate your data if necessary and pass it to the parent. It is necessary to use the `instance_descriptor` decorator as shown above to allow `class_member` option to function correctly. If the `Property` will not be a `class_member`, this decorator can be skipped.
19+
Basically, check the types, manipulate your data if necessary and pass it to the parent. It is necessary to use the `instance_descriptor` decorator as shown above to allow `class_member` option to function correctly. If the `Property` will not be a `class_member`, this decorator can be skipped.
2020

2121
Further, the parent class [`Property` takes care](https://github.com/VigneshVSV/hololinked/blob/main/hololinked/server/property.py) of allocating an instance variable, checking `constant`, `readonly`, pushing change events, writing the value to the database etc. To avoid double checking of certain options like `readonly` and `constant`, its better to carry out the validation and coercion within the method `validate_and_adapt()` instead of `__set__`:
2222

23-
```py title='Validation and Adaption' linenums="1"
24-
--8<-- "docs/howto/code/properties/extending.py:4:6"
25-
--8<-- "docs/howto/code/properties/extending.py:20:37"
23+
```py title='Validation and Adaption' linenums="1"
24+
--8<-- "docs/beginners-guide/code/properties/extending.py:4:6"
25+
--8<-- "docs/beginners-guide/code/properties/extending.py:20:37"
2626
```
2727

28-
The `__set__()` method automatically invokes `validate_and_adapt()`, therefore the new value or validated value can be returned from this method.
28+
The `__set__()` method automatically invokes `validate_and_adapt()`, therefore the new value or validated value can be returned from this method.
2929

3030
To use the `JPEG` property in a `Thing` class, follow the normal procedure of property instantiation:
3131

3232
```py title="Instantiating Custom Property" linenums="1"
33-
--8<-- "docs/howto/code/properties/extending.py:62:76"
33+
--8<-- "docs/beginners-guide/code/properties/extending.py:62:76"
3434
```
3535

36-
In this particular example, since we dont want the `JPEG` to be set externally by a client, we create a local `Property` which carries out the image manipulation and an externally visible `readonly` Property that can fetch the processed image.
36+
In this particular example, since we dont want the `JPEG` to be set externally by a client, we create a local `Property` which carries out the image manipulation and an externally visible `readonly` Property that can fetch the processed image.
3737

38-
The difference between using a custom setter/`fset` method and overloading the `Property` is that, one can accept certain options specific to the `Property` in the `__init__` of the
39-
`Property`:
38+
The difference between using a custom setter/`fset` method and overloading the `Property` is that, one can accept certain options specific to the `Property` in the `__init__` of the
39+
`Property`:
4040

4141
```py title="Reusing Custom Property" linenums="1"
42-
--8<-- "docs/howto/code/properties/extending.py:64:65"
43-
--8<-- "docs/howto/code/properties/extending.py:78:86"
42+
--8<-- "docs/beginners-guide/code/properties/extending.py:64:65"
43+
--8<-- "docs/beginners-guide/code/properties/extending.py:78:86"
4444
```
4545

4646
!!! Note
4747

48-
This is a contrived example and may not lead to optimized Property APIs for the client. Please adapt them suitably or rethink their implementation.
49-
48+
This is a contrived example and may not lead to optimized Property APIs for the client. Please adapt them suitably or rethink their implementation.
5049

5150
One may also use slots to store the attributes of the `Property`. Most properties predefined in this package use slots:
5251

53-
```py title="Using slots" linenums="1"
54-
--8<-- "docs/howto/code/properties/extending.py:90:"
55-
```
52+
```py title="Using slots" linenums="1"
53+
--8<-- "docs/beginners-guide/code/properties/extending.py:90:"
54+
```

0 commit comments

Comments
 (0)