8000 Improved documentation · FirebirdSQL/python3-base@b18c90f · GitHub
[go: up one dir, main page]

Skip to content

Commit b18c90f

Browse files
committed
Improved documentation
1 parent 5c01228 commit b18c90f

23 files changed

+2827
-922
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010

1111
- `firebird.base.buffer.MemoryBuffer.get_raw` method.
1212
- `get_raw` method to `BufferFactory`, `BytesBufferFactory` and `CTypesBufferFactory`.
13+
- `__repr__` method for `PyCode` and `PyCallable` that will limit output to 50 characters.
1314

1415
### Changed
1516

@@ -29,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2930
- Parameter `context` was removed from `firebird.base.trace.traced` decorator.
3031
- Option `context` was removed from `firebird.base.trace.BaseTraceConfig`.
3132
- Log function return value as `repr` rather than `str`.
33+
- Sentinel objects completely reworked. Individual sentinels are now classes derived from `Sentinel`.
3234

3335
### Fixed
3436

docs/buffer.txt

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,45 @@ buffer - Memory buffer manager
88
Overview
99
========
1010

11-
This module provides a raw memory buffer manager with convenient methods to read/write
12-
data of various data type.
11+
This module provides a `MemoryBuffer` class for managing raw memory buffers,
12+
offering a convenient and consistent API for reading and writing various data types
13+
(integers of different sizes, strings with different termination/prefixing styles, raw bytes).
14+
It's particularly useful for tasks involving binary data serialization/deserialization,
15+
such as implementing network protocols or handling custom file formats.
16+
17+
The underlying memory storage can be customized via a `BufferFactory`. Two factories
18+
are provided:
19+
20+
- `BytesBufferFactory`: Uses Python's built-in `bytearray`.
21+
- `CTypesBufferFactory`: Uses `ctypes.create_string_buffer` for potentially different
22+
memory characteristics or C-level interoperability.
23+
24+
Example::
25+
26+
from firebird.base.buffer import MemoryBuffer, ByteOrder
27+
28+
# Create a buffer (default uses bytearray)
29+
buf = MemoryBuffer(10) # Initial size 10 bytes
30+
31+
# Write data
32+
buf.write_short(258) # Write 2 bytes (0x0102 in little-endian)
33+
buf.write_pascal_string("Hi") # Write 1 byte length (2) + "Hi"
34+
buf.write(b'\\x0A\\x0B') # Write raw bytes
35+
36+
# Reset position to read
37+
buf.pos = 0
38+
39+
# Read data
40+
num = buf.read_short()
41+
s = buf.read_pascal_string()
42+
extra = buf.read(2)
43+
44+
print(f"Number: {num}") # Output: Number: 258
45+
print(f"String: '{s}'") # Output: String: 'Hi'
46+
print(f"Extra bytes: {extra}") # Output: Extra bytes: b'\\n\\x0b'
47+
print(f"Final position: {buf.pos}") # Output: Final position: 7
48+
print(f"Raw buffer: {buf.get_raw()}") # Output: Raw buffer: bytearray(b'\\x02\\x01\\x02Hi\\n\\x0b\\x00\\x00\\x00')
49+
1350

1451
MemoryBuffer
1552
============
@@ -21,3 +58,6 @@ Buffer factories
2158
.. autoclass:: BytesBufferFactory
2259
.. autoclass:: CTypesBufferFactory
2360

61+
Functions
62+
=========
63+
.. autofunction:: safe_ord

docs/changelog.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Version 2.0.0 (unreleased)
1313
- Change: Function `Conjunctive` renamed to `.conjunctive`.
1414
- Fix: `.Distinct` support for dataclasses was broken.
1515
- Fix: `.Distinct` support for `hash` was broken.
16+
- Change: Sentinel objects completely reworked. Individual sentinels are now classes
17+
derived from `.Sentinel`.
18+
- Added: `__repr__` method for `.PyCode` and `.PyCallable` that will limit output to 50 characters.
1619

1720
* `~firebird.base.buffer` module:
1821

docs/hooks.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ hooks - Hook manager
88
Overview
99
========
1010

11-
This module provides a general framework for callbacks and "hookable" events.
11+
This module provides a general framework for callbacks and "hookable" events,
12+
implementing a variation of the publish-subscribe pattern. It allows different
13+
parts of an application to register interest in events triggered by specific
14+
objects or classes and execute custom code (callbacks) when those events occur.
1215

1316
Architecture
1417
------------
@@ -155,3 +158,7 @@ Globals
155158
=======
156159
.. autodata:: hook_manager
157160
:no-value:
161+
162+
Dataclasses
163+
===========
164+
.. autoclass:: Hook

docs/logging.txt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,77 @@ belong to default domain specifid in `.LoggingManager.default_domain`, which is
118118
It's also possible to change agent identification used for logger name mapping porposes to
119119
different value with `.set_agent_mapping` function.
120120

121+
Lazy Formatting Messages
122+
------------------------
123+
This module also provides message wrapper classes (`FStrMessage`, `BraceMessage`,
124+
`DollarMessage`) that defer string formatting until the log record is actually
125+
processed by a handler. This avoids the performance cost of formatting messages
126+
that might be filtered out due to log levels.
127+
128+
Basic Setup Example
129+
-------------------
130+
131+
.. code-block:: python
132+
133+
import logging
134+
from firebird.base.logging import (
135+
get_logger, LogLevel, ContextFilter, logging_manager,
136+
DOMAIN, TOPIC # For logger_fmt
137+
)
138+
139+
# 1. Configure standard logging (handlers, formatters)
140+
log_format = "[%(levelname)-8s] %(asctime)s %(name)s (%(agent)s) - %(message)s"
141+
formatter = logging.Formatter(log_format)
142+
handler = logging.StreamHandler()
143+
handler.setFormatter(formatter)
144+
145+
# 2. Add ContextFilter to handler(s) to ensure context fields exist
146+
handler.addFilter(ContextFilter())
147+
148+
# 3. Get the root logger or specific standard loggers and add the handler
149+
root_logger = logging.getLogger()
150+
root_logger.addHandler(handler)
151+
root_logger.setLevel(LogLevel.DEBUG) # Use LogLevel enum or logging constants
152+
153+
# 4. (Optional) Configure logging_manager mappings
154+
logging_manager.logger_fmt = ['app', DOMAIN, TOPIC] # Logger name format
155+
logging_manager.default_domain = 'web' # Default domain if not mapped
156+
logging_manager.set_domain_mapping('db', ['myapp.database.Connection']) # Map agent to domain
157+
158+
# 5. Use in your code
159+
class RequestHandler:
160+
_agent_name_ = 'myapp.web.RequestHandler' # Optional explicit agent name
161+
log_context = None # Can be set per request, e.g., client IP
162+
163+
def handle(self, request_id):
164+
self.log_context = f"ReqID:{request_id}"
165+
logger = get_logger(self, topic='requests') # Get context logger
166+
logger.info("Handling request...")
167+
# ... processing ...
168+
logger.debug("Request handled successfully.")
169+
170+
class DbConnection:
171+
_agent_name_ = 'myapp.database.Connection'
172+
log_context = None # e.g., DB user
173+
174+
def query(self, sql):
175+
self.log_context = "user:admin"
176+
logger = get_logger(self) # Use default topic (None)
177+
logger.debug("Executing query: %s", sql) # Standard formatting works too
178+
# ... execute ...
179+
180+
# --- Execution ---
181+
handler_instance = RequestHandler()
182+
db_conn = DbConnection()
183+
184+
handler_instance.handle("12345")
185+
db_conn.query("SELECT * FROM T")
186+
187+
# --- Example Output ---
188+
# [INFO ] 2023-10-27... app.web.requests (myapp.web.RequestHandler) - Handling request...
189+
# [DEBUG ] 2023-10-27... app.web.requests (myapp.web.RequestHandler) - Request handled successfully.
190+
# [DEBUG ] 2023-10-27... app.db (myapp.database.Connection) - Executing query: SELECT * FROM T
191+
121192
Enums & Flags
122193
=============
123194
.. autoclass:: FormatElement

docs/protobuf.txt

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,66 @@ protobuf - Registry for Google Protocol Buffer messages and enums
88
Overview
99
========
1010

11-
This module provides central registry for Google Protocol Buffer messages and enums.
12-
The generated `*_pb2.py` protobuf files could be registered using `register_decriptor`
13-
or `load_registered` function. The registry could be then used to obtain information
14-
about protobuf messages or enum types, or to create message instances or enum values.
11+
This module provides a central registry for Google Protocol Buffer message types
12+
and enum types generated from `.proto` files. It allows creating message instances
13+
and accessing enum information using their fully qualified names (e.g.,
14+
"my.package.MyMessage", "my.package.MyEnum") without needing to directly import
15+
the corresponding generated `_pb2.py` modules throughout the codebase.
16+
17+
Benefits:
18+
19+
* Decouples code using protobuf messages from the specific generated modules.
20+
* Provides a single point for managing and discovering available message/enum types.
21+
* Facilitates dynamic loading of protobuf definitions via entry points.
22+
23+
Core Features:
24+
25+
* Register message/enum types using their file DESCRIPTOR object.
26+
* Create new message instances by name using `create_message()`.
27+
* Access enum descriptors and values by name using `get_enum_type()`.
28+
* Load protobuf definitions registered by other installed packages via entry points
29+
using `load_registered()`.
30+
* Helpers for common types like `google.protobuf.Struct`.
31+
32+
Example::
33+
34+
# Assume you have my_proto_pb2.py generated from my_proto.proto
35+
# containing:
36+
# message Sample { required string name = 1; }
37+
# enum Status { UNKNOWN = 0; OK = 1; ERROR = 2; }
38+
39+
from firebird.base.protobuf import (
40+
register_descriptor, create_message, get_enum_type, is_msg_registered
41+
)
42+
# Import the generated descriptor (only needed once, e.g., at startup)
43+
try:
44+
from . import my_proto_pb2 # Replace with actual import path
45+
HAS_MY_PROTO = True
46+
except ImportError:
47+
HAS_MY_PROTO = False
48+
49+
# 1. Register the types from the descriptor
50+
if HAS_MY_PROTO:
51+
register_descriptor(my_proto_pb2.DESCRIPTOR)
52+
print(f"Is 'my_proto.Sample' registered? {is_msg_registered('my_proto.Sample')}")
53+
54+
# 2. Create a message instance by name
55+
if HAS_MY_PROTO:
56+
try:
57+
msg = create_message('my_proto.Sample')
58+
msg.name = "Example"
59+
print(f"Created message: {msg}")
60+
61+
# 3. Access enum type and values by name
62+
status_enum = get_enum_type('my_proto.Status')
63+
print(f"Status enum name: {status_enum.name}")
64+
print(f"OK value: {status_enum.OK}") # Access like attribute
65+
print(f"Name for value 2: {status_enum.get_value_name(2)}") # Access via method
66+
print(f"Available status keys: {status_enum.keys()}")
67+
68+
except KeyError as e:
69+
print(f"Error accessing registered proto type: {e}")
70+
1571

1672
Constants
1773
=========

docs/signal.txt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@ signal - Callback system based on Signals and Slots, and "Delphi events"
88
Overview
99
========
1010

11-
This module provides two callback mechanisms: one based on signals and slots similar to Qt
12-
signal/slot, and second based on optional method delegation similar to events in Delphi.
11+
This module provides two callback mechanisms:
1312

14-
In both cases, the callback callables could be functions, instance or class methods,
15-
partials and lambda functions. The `inspect` module is used to define the signature for
16-
callbacks, and to validate that only compatible callables are assigned.
13+
1. Signals and Slots (`.Signal`, `.signal` decorator): Inspired by Qt, a signal
14+
can be connected to multiple slots (callbacks). When the signal is emitted,
15+
all connected slots are called. Return values from slots are ignored.
16+
2. Eventsockets (`.eventsocket` decorator): Similar to Delphi events, an
17+
eventsocket holds a reference to a *single* slot (callback). Assigning a new
18+
slot replaces the previous one. Calling the eventsocket delegates the call
19+
directly to the connected slot. Return values are passed back from the slot.
20+
21+
In both cases, slots can be functions, instance/class methods, `functools.partial`
22+
objects, or lambda functions. The `inspect` module is used to enforce signature
23+
matching between the signal/eventsocket definition and the connected slots.
1724

1825
.. important::
1926

@@ -175,16 +182,10 @@ Classes
175182
=======
176183

177184
.. autoclass:: Signal
178-
179-
------------
180-
181185
.. autoclass:: _EventSocket
182186

183187
Decorators
184188
==========
185189

186190
.. autoclass:: signal
187-
188-
-----------
189-
190191
.. autoclass:: eventsocket

docs/trace.txt

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,20 @@ logging provided by `.logging` module.
1414
The trace logging is performed by `traced` decorator. You can use this decorator directly,
1515
or use `TracedMixin` class to automatically decorate methods of class instances on creation.
1616
Each decorated callable could log messages before execution, after successful execution or
17-
on failed execution (when unhandled execption is raised by callable). The trace decorator
17+
on failed execution (when unhandled exception is raised by callable). The trace decorator
1818
can automatically add `agent` and `context` information, and include parameters passed to
1919
callable, execution time, return value, information about raised exception etc. to log messages.
2020

21-
The trace logging is managed by `TraceManager`, that allows dynamic configuration of traced
22-
callables at runtime.
21+
Trace behavior can be configured dynamically at runtime using the `TraceManager`.
22+
This includes:
23+
24+
* Enabling/disabling tracing globally or for specific aspects (before/after/fail).
25+
* Registering classes whose methods should be traced.
26+
* Adding specific trace configurations (like custom messages or levels) for
27+
individual methods using `TraceManager.add_trace()`.
28+
* Loading comprehensive trace configurations from `ConfigParser` files using
29+
`TraceManager.load_config()`, which allows specifying traced classes, methods,
30+
and decorator parameters via INI-style sections (see `TraceConfig`).
2331

2432
Example
2533
=======
@@ -416,18 +424,16 @@ Trace configuration classes
416424

417425
.. autoclass:: BaseTraceConfig
418426

419-
------------------
420-
421427
.. autoclass:: TracedMethodConfig
422428
:no-inherited-members:
423429

424-
-----------------
425-
426430
.. autoclass:: TracedClassConfig
427431
:no-inherited-members:
428432

429-
-----------
430-
431433
.. autoclass:: TraceConfig
432434
:no-inherited-members:
433435

436+
Dataclasses
437+
===========
438+
.. autoclass:: TracedItem
439+
.. autoclass:: TracedClass

docs/types.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ One such approach uses custom descendants of builtin `str` type.
125125
.. caution::
126126

127127
Custom string types have an inherent weakness. They support all inherited string methods,
128-
but any method that returns string value return a base `str` type, not the decendant class
128+
but any method that returns string value return a base `str` type, not the descendant class
129129
type. That same apply when you assign strings to variables that should be of custom
130130
string type.
131131

@@ -146,7 +146,7 @@ Meta classes
146146
============
147147

148148
.. autoclass:: SingletonMeta
149-
.. autoclass:: SentinelMeta
149+
.. autoclass:: _SentinelMeta
150150
.. autoclass:: CachedDistinctMeta
151151
.. autofunction:: conjunctive
152152

0 commit comments

Comments
 (0)
0