Skip to content

Commit a787496

Browse files
committed
wip readme: basic usage + with_strict_types tutorial
1 parent d74144c commit a787496

File tree

6 files changed

+215
-7
lines changed

6 files changed

+215
-7
lines changed

README.md

Lines changed: 141 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,166 @@
44
[![format](https://github.com/SpectraL519/pyconstclasses/actions/workflows/format.yaml/badge.svg)](https://github.com/SpectraL519/pyconstclasses/actions/workflows/format)
55
[![coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/SpectraL519/f6cec4c4c8e1733cfe45f807918a128a/raw/covbadge.json)]()
66

7-
> [!IMPORTANT]
8-
> This readme file will be extended later in the development process
9-
107
<br />
118

129
## Overview
1310

14-
`PyConstClasses` is a python package containing const class decorators and utility. It allows for the creation constant and static constant classes by utilizing the annotations of the
11+
`PyConstClasses` is a python package containing const class decorators and utility. It allows for the creation constant and static constant classes by utilizing the annotations of the class definition.
1512

1613
<br />
1714
<br />
1815

1916
## Table of contents
2017

2118
* Installation
22-
* Tutorial
19+
* [Tutorial](#tutorial)
20+
* [Basic usage](#basic-usage)
2321
* Examples
2422
* [Dev notes](#dev-notes)
2523
* [Licence](#licence)
2624

25+
<br />
26+
<br />
27+
28+
## Tutorial
29+
30+
After installing the package, you have to import it to your python program:
31+
```python
32+
import constclasses as cc
33+
```
34+
35+
### Basic usage
36+
37+
The core of the PyConstClasses package are the `const_class` and `static_const_class` decorators. Both of these decorators override the default behaviour of the `__setattr__` magic method for the decorated class so that it thors `cc.ConstError` when trying to modify the constant attribute of an instance.
38+
39+
* The `const_class` decorator allows you to define a class structure and create constant instances of the defined class:
40+
41+
```python
42+
# const_class_basic.py
43+
44+
@cc.const_class
45+
class Person:
46+
first_name: str
47+
last_name: str
48+
49+
def __repr__(self) -> str:
50+
return f"{self.first_name} {self.last_name}"
51+
52+
53+
if __name__ == "__main__":
54+
john = Person("John", "Doe")
55+
print(john)
56+
57+
try:
58+
john.first_name = "Bob"
59+
except cc.ConstError as err:
60+
print(f"Error: {err}")
61+
```
62+
63+
This program will produce the following output:
64+
```
65+
John Doe
66+
Error: Cannot modify const attribute `first_name` of class `Person`
67+
```
68+
69+
* The `static_const_class` deacorator allows you to define a pseudo-static resource with const members (it creates an instance of the decorated class):
70+
71+
```python
72+
# static_const_class_basic.py
73+
74+
@cc.static_const_class
75+
class ProjectConfiguration:
76+
name: str = "MyProject"
77+
version: str = "alpha"
78+
79+
def __repr__(self):
80+
return f"Project: {self.name}\nVersion: {self.version}"
81+
82+
83+
if __name__ == "__main__":
84+
print(ProjectConfiguration)
85+
86+
try:
87+
ProjectConfiguration.version = "beta"
88+
except cc.ConstError as err:
89+
print(f"Error: {err}")
90+
```
91+
92+
This program will produce the following output:
93+
```
94+
Project: MyProject
95+
Version: alpha
96+
Error: Cannot modify const attribute `version` of class `ProjectConfiguration`
97+
```
98+
99+
> [!IMPORTANT]
100+
> In the current version of the package the constant attributes have to be defined using annotations, i.e. the `member: type ( = value)` syntax of the class member declaration is required
101+
102+
<br />
103+
104+
### Common parameters
105+
106+
Both const decorators - `const_class` and `static_const_class` - have the following parameters:
107+
108+
* `with_strict_types: bool`
109+
110+
If this parameter's value is set to
111+
* `False` - the decorators will use the `attribute_type(given_value)` conversion, so as long as the given value's type is convertible to the desired type, the decorators will not raise any errors.
112+
* `True` - the decorators will perform an `isinstance(given_value, attribute_type)` check, the failure of which will result in raising a `TypeError`
113+
114+
Example:
115+
```python
116+
# with_strict_types.py
117+
118+
@cc.const_class
119+
class Person:
120+
first_name: str
121+
last_name: str
122+
age: int
123+
124+
def __repr__(self) -> str:
125+
return f"{self.first_name} {self.last_name} [age: {self.age}]"
126+
127+
@cc.const_class(with_strict_types=True)
128+
class PersonStrictTypes:
129+
first_name: str
130+
last_name: str
131+
age: int
132+
133+
def __repr__(self) -> str:
134+
return f"{self.first_name} {self.last_name} [age: {self.age}]"
135+
136+
137+
if __name__ == "__main__":
138+
john = Person("John", "Doe", 21.5)
139+
print(john)
140+
141+
try:
142+
# invalid as 21.5 is not an instance of int
143+
john_strict = PersonStrictTypes("John", "Doe", 21.5)
144+
except TypeError as err:
145+
print(f"Error:\n{err}")
146+
147+
john_strict = PersonStrictTypes("John", "Doe", 21)
148+
print(john_strict)
149+
```
150+
151+
This program will produce the following output:
152+
```
153+
John Doe [age: 21]
154+
Error:
155+
Attribute value does not match the declared type:
156+
attribute: age, declared type: <class 'int'>, actual type: <class 'float'>
157+
John Doe [age: 21]
158+
```
159+
160+
161+
27162
<br />
28163
<br />
29164

30165
## Dev notes
166+
<!-- TODO: extract to sepparate file -->
31167

32168
* export requirements: `pip freeze > requirements-dev.txt`
33169
* install requirements: `pip install -r requirements-dev.txt`

examples/const_class_basic.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import constclasses as cc
2+
3+
@cc.const_class
4+
class Person:
5+
first_name: str
6+
last_name: str
7+
8+
def __repr__(self) -> str:
9+
return f"{self.first_name} {self.last_name}"
10+
11+
12+
if __name__ == "__main__":
13+
john = Person("John", "Doe")
14+
print(john)
15+
16+
try:
17+
john.first_name = "Bob"
18+
except cc.ConstError as err:
19+
print(f"Error: {err}")

examples/static_const_class_basic.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import constclasses as cc
2+
3+
@cc.static_const_class
4+
class ProjectConfiguration:
5+
name: str = "MyProject"
6+
version: str = "alpha"
7+
8+
def __repr__(self):
9+
return f"Project: {self.name}\nVersion: {self.version}"
10+
11+
12+
if __name__ == "__main__":
13+
print(ProjectConfiguration)
14+
15+
try:
16+
ProjectConfiguration.version = "beta"
17+
except cc.ConstError as err:
18+
print(f"Error: {err}")

examples/with_strict_types.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import constclasses as cc
2+
3+
4+
@cc.const_class
5+
class Person:
6+
first_name: str
7+
last_name: str
8+
age: int
9+
10+
def __repr__(self) -> str:
11+
return f"{self.first_name} {self.last_name} [age: {self.age}]"
12+
13+
@cc.const_class(with_strict_types=True)
14+
class PersonStrictTypes:
15+
first_name: str
16+
last_name: str
17+
age: int
18+
19+
def __repr__(self) -> str:
20+
return f"{self.first_name} {self.last_name} [age: {self.age}]"
21+
22+
23+
if __name__ == "__main__":
24+
john = Person("John", "Doe", 21.5)
25+
print(john)
26+
27+
try:
28+
# invalid as 21.5 is not an instance of int
29+
john_strict = PersonStrictTypes("John", "Doe", 21.5)
30+
except TypeError as err:
31+
print(f"Error:\n{err}")
32+
33+
john_strict = PersonStrictTypes("John", "Doe", 21)
34+
print(john_strict)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
55

66
[project]
77
name = "pyconstclasses"
8-
version = "0.8"
8+
version = "1.0"
99
description = "Package with const class decoratos and utility"
1010
authors = [
1111
{name = "SpectraL519"}

src/constclasses/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
from .ccerror import ConstError, InitializationError
1+
from .ccerror import ConstError, InitializationError, ConfigurationError
22
from .const_class import const_class
3+
from .static_const_class import static_const_class, mutable_instance

0 commit comments

Comments
 (0)