API Reference¶
This page documents the public API of Pure3270.
Main Module¶
pure3270 package init. Exports core classes and functions for 3270 terminal emulation.
- class pure3270.Session(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2')[source]¶
Bases:
objectSynchronous wrapper for AsyncSession.
This class provides a synchronous interface to the asynchronous 3270 session. All methods use asyncio.run() to execute async operations.
- __init__(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2') None[source]¶
Initialize a synchronous session with a dedicated thread and event loop.
- connect(host: str | None = None, port: int | None = None, ssl_context: Any | None = None) None[source]¶
Connect to the 3270 host synchronously.
- Parameters:
host – Optional host override.
port – Optional port override (default 23).
ssl_context – Optional SSL context override.
- Raises:
ConnectionError – If connection fails.
- send(data: bytes) None[source]¶
Send data to the session.
- Parameters:
data – Bytes to send.
- Raises:
SessionError – If send fails.
- read(timeout: float = 5.0) bytes[source]¶
Read data from the session.
- Parameters:
timeout – Read timeout in seconds.
- Returns:
Received bytes.
- Raises:
SessionError – If read fails.
- property screen_buffer: ScreenBuffer¶
Expose screen buffer for sync Session tests.
- property tn3270e_mode: bool¶
Check if session is in TN3270E mode.
Preference order: 1) Async session’s tn3270 mode flag when True 2) Handler’s negotiated_tn3270e flag as a fallback
- ascii(data: bytes) str[source]¶
Convert EBCDIC data to ASCII text (s3270 Ascii() action).
- Parameters:
data – EBCDIC bytes to convert.
- Returns:
ASCII string representation.
- ebcdic(text: str) bytes[source]¶
Convert ASCII text to EBCDIC data (s3270 Ebcdic() action).
- Parameters:
text – ASCII text to convert.
- Returns:
EBCDIC bytes representation.
- ascii1(byte_val: int) str[source]¶
Convert a single EBCDIC byte to ASCII character.
This is a pure conversion utility and does not require a live session.
- ebcdic1(char: str) int[source]¶
Convert a single ASCII character to EBCDIC byte.
This is a pure conversion utility and does not require a live session.
- ascii_field(field_index: int) str[source]¶
Convert field content to ASCII text (s3270 AsciiField() action).
- Parameters:
field_index – Index of field to convert.
- Returns:
ASCII string representation of field content.
- cursor_select() None[source]¶
Select field at cursor (s3270 CursorSelect() action).
- Raises:
SessionError – If not connected.
- delete_field() None[source]¶
Delete field at cursor (s3270 DeleteField() action).
- Raises:
SessionError – If not connected.
- circum_not() None[source]¶
Toggle circumvention of field protection (s3270 CircumNot() action).
- Raises:
SessionError – If not connected.
- script(commands: str) None[source]¶
Execute script (s3270 Script() action).
- Parameters:
commands – Script commands.
- Raises:
SessionError – If not connected.
- query(query_type: str = 'All') str[source]¶
Query session information synchronously.
- Supported query types (s3270 protocol parity):
All: Summary information
CodePage: Host code page
ConnectionState: Connection state
Cursor: Cursor position
Model: 3270 model information
ScreenCurSize: Current screen dimensions
Tn3270eOptions: Active TN3270E functions
TelnetHostOptions: Host TELNET options
TelnetMyOptions: Client TELNET options
And 30+ more query types…
- move_cursor1(row: int, col: int) None[source]¶
Move cursor to specified position (s3270 MoveCursor1 action).
- class pure3270.AsyncSession(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2', is_printer_session: bool = False)[source]¶
Bases:
objectAsynchronous 3270 session handler.
This class provides an asynchronous interface to the 3270 session. All operations are async and use asyncio for non-blocking I/O.
- AID_MAP: Dict[str, int] = {'Attn': 241, 'BackSpace': 248, 'CLEAR': 109, 'Dup': 245, 'Enter': 125, 'PA(1)': 108, 'PA(2)': 110, 'PA(3)': 107, 'PF(1)': 241, 'PF(10)': 122, 'PF(11)': 123, 'PF(12)': 124, 'PF(13)': 193, 'PF(14)': 194, 'PF(15)': 195, 'PF(16)': 196, 'PF(17)': 197, 'PF(18)': 198, 'PF(19)': 199, 'PF(2)': 242, 'PF(20)': 200, 'PF(21)': 201, 'PF(22)': 74, 'PF(23)': 75, 'PF(24)': 76, 'PF(3)': 243, 'PF(4)': 244, 'PF(5)': 245, 'PF(6)': 246, 'PF(7)': 247, 'PF(8)': 248, 'PF(9)': 249, 'RESET': 106, 'SysReq': 240, 'TEST': 17, 'Test': 17}¶
- __init__(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2', is_printer_session: bool = False) None[source]¶
Initialize the AsyncSession.
- Parameters:
host – Host to connect to.
port – Port to connect to.
ssl_context – SSL context for secure connections.
force_mode – Force specific TN3270 mode.
allow_fallback – Allow fallback to TN3270 if TN3270E fails.
enable_trace – Enable tracing.
terminal_type – Terminal model type.
is_printer_session – True if this is a printer session.
- property screen_buffer: ScreenBuffer¶
Get the screen buffer.
- property screen: ScreenBuffer¶
Get the screen buffer (alias for screen_buffer).
- property handler: TN3270Handler | None¶
Get the underlying TN3270 handler (may be None if not connected).
- async connect(host: str | None = None, port: int | None = None, ssl_context: Any | None = None) None[source]¶
Connect to the 3270 host asynchronously.
- async receive_data(timeout: float = 5.0) bytes[source]¶
Receive data from the session (alias for read).
- managed() AsyncIterator[AsyncSession][source]¶
Provide a managed async context that guarantees close() on exit.
- async script(commands: str) None[source]¶
Execute script command(s).
Supports both simple method names and function-style commands like: - Simple: “connect”, “disconnect” - With args: “String(test)”, “MoveCursor(5,10)”
- async set_option(option: str, value: str) None[source]¶
Set option (placeholder for future functionality).
- async delete() None[source]¶
Delete character at cursor by shifting remainder left and clearing last.
- async send_file(local_path: str, remote_name: str) None[source]¶
Send a file to the host using IND$FILE protocol.
- async receive_file(remote_name: str, local_path: str) None[source]¶
Receive a file from the host using IND$FILE protocol.
- class pure3270.PrinterSession[source]¶
Bases:
objectAdvanced TN3270E printer session handler with comprehensive SCS support.
- start_new_job(job_id: str = '') PrinterJob[source]¶
Start a new printer job.
- add_scs_data(data: bytes, holding_lock: bool = False) None[source]¶
Add SCS character data to the current job.
- Parameters:
data – SCS data to add
holding_lock – True if caller already holds self.lock (internal use only)
- get_current_job() PrinterJob | None[source]¶
Get the current active job.
- get_completed_jobs() List[PrinterJob][source]¶
Get the list of completed jobs.
- handle_scs_control_code(scs_code: int) None[source]¶
Handle SCS control codes with comprehensive support.
- process_tn3270e_message(header: TN3270EHeader, data: bytes) None[source]¶
Process a TN3270E message for printer session with comprehensive support.
- class pure3270.P3270Client(hostName: str | None = None, hostPort: int = 23, ssl: bool = False, *args: Any, **kwargs: Any)[source]¶
Bases:
object- connect() None[source]¶
Establish connection to TN3270 host using pure3270.Session. If no hostName is configured, perform a no-op to match legacy client behavior in test harnesses that call connect() without specifying a host.
- numOfInstances = 0¶
- __init__(hostName: str | None = None, hostPort: int = 23, ssl: bool = False, *args: Any, **kwargs: Any) None[source]¶
Initialize P3270Client with hostName and hostPort, matching p3270 API.
- sendText(text: str, asterisks: bool = False) None[source]¶
Send text to the current cursor position.
- Parameters:
text – Text to send
asterisks – If True, mask input (for passwords)
- makeArgs(*args: Any) List[Any][source]¶
Return a list constructed from provided args (legacy helper).
Mirrors p3270.P3270Client.makeArgs behavior by simply returning a list of the arguments passed, used by some calling code that expects an args list for command assembly.
- readTextAtPosition(row: int, col: int, length: int) str[source]¶
Read text at specified position.
- Parameters:
row – Row position (0-based)
col – Column position (0-based)
length – Number of characters to read
- Returns:
Text at the specified position
- readTextArea(startRow: int, startCol: int, endRow: int, endCol: int) str[source]¶
Read text from a rectangular area.
- Parameters:
startRow – Starting row (0-based)
startCol – Starting column (0-based)
endRow – Ending row (0-based)
endCol – Ending column (0-based)
- Returns:
Text from the specified area
- foundTextAtPosition(row: int, col: int, text: str) bool[source]¶
Check if specific text is found at position.
- Parameters:
row – Row position (0-based)
col – Column position (0-based)
text – Text to search for
- Returns:
True if text is found at position
- trySendTextToField(text: str, row: int | None = None, col: int | None = None) bool[source]¶
Try to send text to a specific field.
- Parameters:
text – Text to send
row – Row position (optional)
col – Column position (optional)
- Returns:
True if successful
- waitForCursorAt(row: int, col: int, timeout: float = 5.0) bool[source]¶
Wait for cursor to be at specific position.
- waitForCursorAtOffset(offset: int, timeout: float = 5.0) bool[source]¶
Wait for cursor at specific offset from start of screen.
- waitForStringAt(row: int, col: int, text: str, timeout: float = 5.0) bool[source]¶
Wait for specific text to appear at position.
- waitForStringAtOffset(offset: int, text: str, timeout: float = 5.0) bool[source]¶
Wait for specific text to appear at offset.
- waitForFieldAt(row: int, col: int, timeout: float = 5.0) bool[source]¶
Wait for input field at specific position.
Session Module¶
Session management for pure3270, handling synchronous and asynchronous 3270 connections.
- exception pure3270.session.SessionError(message: str, context: Dict[str, Any] | None = None)[source]¶
Bases:
ExceptionBase exception for session-related errors.
When context is provided, include key details in the string representation so tests can assert on them without reaching into attributes.
- exception pure3270.session.ConnectionError(message: str, context: Dict[str, Any] | None = None)[source]¶
Bases:
SessionErrorRaised when connection fails.
- class pure3270.session.Session(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2')[source]¶
Bases:
objectSynchronous wrapper for AsyncSession.
This class provides a synchronous interface to the asynchronous 3270 session. All methods use asyncio.run() to execute async operations.
- __init__(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2') None[source]¶
Initialize a synchronous session with a dedicated thread and event loop.
- connect(host: str | None = None, port: int | None = None, ssl_context: Any | None = None) None[source]¶
Connect to the 3270 host synchronously.
- Parameters:
host – Optional host override.
port – Optional port override (default 23).
ssl_context – Optional SSL context override.
- Raises:
ConnectionError – If connection fails.
- send(data: bytes) None[source]¶
Send data to the session.
- Parameters:
data – Bytes to send.
- Raises:
SessionError – If send fails.
- read(timeout: float = 5.0) bytes[source]¶
Read data from the session.
- Parameters:
timeout – Read timeout in seconds.
- Returns:
Received bytes.
- Raises:
SessionError – If read fails.
- property screen_buffer: ScreenBuffer¶
Expose screen buffer for sync Session tests.
- property tn3270e_mode: bool¶
Check if session is in TN3270E mode.
Preference order: 1) Async session’s tn3270 mode flag when True 2) Handler’s negotiated_tn3270e flag as a fallback
- ascii(data: bytes) str[source]¶
Convert EBCDIC data to ASCII text (s3270 Ascii() action).
- Parameters:
data – EBCDIC bytes to convert.
- Returns:
ASCII string representation.
- ebcdic(text: str) bytes[source]¶
Convert ASCII text to EBCDIC data (s3270 Ebcdic() action).
- Parameters:
text – ASCII text to convert.
- Returns:
EBCDIC bytes representation.
- ascii1(byte_val: int) str[source]¶
Convert a single EBCDIC byte to ASCII character.
This is a pure conversion utility and does not require a live session.
- ebcdic1(char: str) int[source]¶
Convert a single ASCII character to EBCDIC byte.
This is a pure conversion utility and does not require a live session.
- ascii_field(field_index: int) str[source]¶
Convert field content to ASCII text (s3270 AsciiField() action).
- Parameters:
field_index – Index of field to convert.
- Returns:
ASCII string representation of field content.
- cursor_select() None[source]¶
Select field at cursor (s3270 CursorSelect() action).
- Raises:
SessionError – If not connected.
- delete_field() None[source]¶
Delete field at cursor (s3270 DeleteField() action).
- Raises:
SessionError – If not connected.
- circum_not() None[source]¶
Toggle circumvention of field protection (s3270 CircumNot() action).
- Raises:
SessionError – If not connected.
- script(commands: str) None[source]¶
Execute script (s3270 Script() action).
- Parameters:
commands – Script commands.
- Raises:
SessionError – If not connected.
- query(query_type: str = 'All') str[source]¶
Query session information synchronously.
- Supported query types (s3270 protocol parity):
All: Summary information
CodePage: Host code page
ConnectionState: Connection state
Cursor: Cursor position
Model: 3270 model information
ScreenCurSize: Current screen dimensions
Tn3270eOptions: Active TN3270E functions
TelnetHostOptions: Host TELNET options
TelnetMyOptions: Client TELNET options
And 30+ more query types…
- move_cursor1(row: int, col: int) None[source]¶
Move cursor to specified position (s3270 MoveCursor1 action).
- class pure3270.session.AsyncSession(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2', is_printer_session: bool = False)[source]¶
Bases:
objectAsynchronous 3270 session handler.
This class provides an asynchronous interface to the 3270 session. All operations are async and use asyncio for non-blocking I/O.
- AID_MAP: Dict[str, int] = {'Attn': 241, 'BackSpace': 248, 'CLEAR': 109, 'Dup': 245, 'Enter': 125, 'PA(1)': 108, 'PA(2)': 110, 'PA(3)': 107, 'PF(1)': 241, 'PF(10)': 122, 'PF(11)': 123, 'PF(12)': 124, 'PF(13)': 193, 'PF(14)': 194, 'PF(15)': 195, 'PF(16)': 196, 'PF(17)': 197, 'PF(18)': 198, 'PF(19)': 199, 'PF(2)': 242, 'PF(20)': 200, 'PF(21)': 201, 'PF(22)': 74, 'PF(23)': 75, 'PF(24)': 76, 'PF(3)': 243, 'PF(4)': 244, 'PF(5)': 245, 'PF(6)': 246, 'PF(7)': 247, 'PF(8)': 248, 'PF(9)': 249, 'RESET': 106, 'SysReq': 240, 'TEST': 17, 'Test': 17}¶
- __init__(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2', is_printer_session: bool = False) None[source]¶
Initialize the AsyncSession.
- Parameters:
host – Host to connect to.
port – Port to connect to.
ssl_context – SSL context for secure connections.
force_mode – Force specific TN3270 mode.
allow_fallback – Allow fallback to TN3270 if TN3270E fails.
enable_trace – Enable tracing.
terminal_type – Terminal model type.
is_printer_session – True if this is a printer session.
- property screen_buffer: ScreenBuffer¶
Get the screen buffer.
- property screen: ScreenBuffer¶
Get the screen buffer (alias for screen_buffer).
- property handler: TN3270Handler | None¶
Get the underlying TN3270 handler (may be None if not connected).
- async connect(host: str | None = None, port: int | None = None, ssl_context: Any | None = None) None[source]¶
Connect to the 3270 host asynchronously.
- async receive_data(timeout: float = 5.0) bytes[source]¶
Receive data from the session (alias for read).
- managed() AsyncIterator[AsyncSession][source]¶
Provide a managed async context that guarantees close() on exit.
- async script(commands: str) None[source]¶
Execute script command(s).
Supports both simple method names and function-style commands like: - Simple: “connect”, “disconnect” - With args: “String(test)”, “MoveCursor(5,10)”
- async set_option(option: str, value: str) None[source]¶
Set option (placeholder for future functionality).
- async delete() None[source]¶
Delete character at cursor by shifting remainder left and clearing last.
- async send_file(local_path: str, remote_name: str) None[source]¶
Send a file to the host using IND$FILE protocol.
- async receive_file(remote_name: str, local_path: str) None[source]¶
Receive a file from the host using IND$FILE protocol.
Patching Module¶
Minimal patching stub to satisfy tests.
The test suite sometimes patches pure3270.patching.enable_replacement; provide a no-op implementation here to avoid AttributeError during tests that import it.
Emulation Modules¶
Screen Buffer¶
Screen buffer management for 3270 emulation.
- class pure3270.emulation.screen_buffer.Field(start: Tuple[int, int], end: Tuple[int, int], protected: bool = False, numeric: bool = False, modified: bool = False, selected: bool = False, intensity: int = 0, color: int = 0, background: int = 0, validation: int = 0, outlining: int = 0, character_set: int = 0, sfe_highlight: int = 0, light_pen: int = 0, content: bytes | None = None, codepage: str = 'cp037')[source]¶
Bases:
objectA simple Field object that mirrors the previous namedtuple API with convenient defaults and helper methods used by tests.
It intentionally implements get_content, set_content, and _replace to be compatible with test expectations. content is stored as raw EBCDIC bytes; get_content/set_content use the EBCDICCodec by default but will fall back to EmulationEncoder when the codec isn’t present.
- __init__(start: Tuple[int, int], end: Tuple[int, int], protected: bool = False, numeric: bool = False, modified: bool = False, selected: bool = False, intensity: int = 0, color: int = 0, background: int = 0, validation: int = 0, outlining: int = 0, character_set: int = 0, sfe_highlight: int = 0, light_pen: int = 0, content: bytes | None = None, codepage: str = 'cp037') None[source]¶
- get_content(codec: EBCDICCodec | None = None) str[source]¶
Return decoded content as a Unicode string.
Accepts an optional codec for decoding; if not provided we use EBCDICCodec() when available, otherwise EmulationEncoder.
- class pure3270.emulation.screen_buffer.ScreenBuffer(rows: int = 24, cols: int = 80, init_value: int = 64, codepage: str = 'cp037')[source]¶
Bases:
BufferWriter- property ascii_buffer: str¶
Return the entire screen buffer as a multi-line ASCII string.
Tests expect exactly rows lines separated by newlines, regardless of trailing blank content. This method converts each row of the EBCDIC buffer to printable ASCII, masking non-printables to spaces, and joins all rows with newlines without trimming.
In ASCII mode, returns the buffer content directly as ASCII text.
- __init__(rows: int = 24, cols: int = 80, init_value: int = 64, codepage: str = 'cp037')[source]¶
Initialize the ScreenBuffer.
- Parameters:
rows – Number of rows (default 24).
cols – Number of columns (default 80).
init_value – Initial value for buffer (default 0x40 for space).
- set_ascii_mode(ascii_mode: bool) None[source]¶
Set ASCII mode for the screen buffer.
In ASCII mode, characters are stored as ASCII bytes directly. In EBCDIC mode (default), characters are converted to EBCDIC.
- Parameters:
ascii_mode – True for ASCII mode, False for EBCDIC mode
- get_field_content(field_index: int) str[source]¶
Return the content of the field at the given index as a decoded string.
- read_modified_fields() list[tuple[tuple[int, int], str]][source]¶
Return a list of tuples (position, content) for modified fields.
- set_position(row: int, col: int, wrap: bool = False, strict: bool = False) None[source]¶
Set cursor position with bounds checking or wrapping.
- Parameters:
row – Target row position
col – Target column position
wrap – If True, allow wrapping to next line; if False, check bounds
strict – If True, raise IndexError on out of bounds; if False, clamp values
- Raises:
IndexError – When strict=True and position is out of bounds
- write_char(ebcdic_byte: int, row: int | None = None, col: int | None = None, protected: bool = False, circumvent_protection: bool = False, mark_field_start: bool = False) None[source]¶
Write an EBCDIC character to the buffer at position.
- Parameters:
ebcdic_byte – EBCDIC byte value.
row – Row position.
col – Column position.
protected – Protection attribute to set.
circumvent_protection – If True, write even to protected fields.
mark_field_start – If True, mark this position as a field start.
- update_from_stream(data: bytes) None[source]¶
Update buffer from a 3270 data stream using proper DataStreamParser for accurate 3270 order handling.
For backward compatibility with tests expecting simple byte sequences, this method detects whether the data appears to be raw bytes (no 3270 orders) vs. actual 3270 data streams.
- Parameters:
data – Raw 3270 data stream bytes.
- to_text() str[source]¶
Convert screen buffer to Unicode text string.
- Returns:
Multi-line string representation.
- get_field_at_position(row: int, col: int) Field | None[source]¶
Get the field containing the given position, if any (optimized with caching).
- move_cursor_to_first_input_field() None[source]¶
Moves the cursor to the beginning of the first unprotected field with performance optimization.
- move_cursor_to_next_input_field() None[source]¶
Moves the cursor to the beginning of the next unprotected, non-skipped, non-autoskip field. Wraps around to the first field if no next field is found.
In ASCII mode, this also considers ASCII fields detected by VT100 parser.
- set_attribute(attr: int, row: int | None = None, col: int | None = None) None[source]¶
Set field attribute at specified or current position.
- repeat_attribute(attr: int, repeat: int) None[source]¶
Repeat attribute a specified number of times.
- set_extended_attribute_sfe(attr_type: int, attr_value: int) None[source]¶
Accumulate extended field attributes for the field at the current buffer address.
Important semantics: - Extended attributes (from SFE or SA) do NOT consume a display byte and
must NOT create a field-start marker on their own.
Only the base field attribute (set via SF or SFE type 0xC0) occupies a buffer position and should be recorded in _field_starts.
This method therefore ONLY updates the accumulated extended attributes and does not modify the display buffer or _field_starts.
- set_extended_attribute(row: int, col: int, attr_type: str, value: int) None[source]¶
Set an extended attribute at a specific position (used by tests and APIs).
This also records a field start at that position to align with field-start-driven detection.
- get_field_at(row: int, col: int) Field | None[source]¶
Alias for get_field_at_position for compatibility.
- get_extended_attributes_at(row: int, col: int) ExtendedAttributeSet | None[source]¶
Get extended attributes for a specific position.
- Parameters:
row – Row position
col – Column position
- Returns:
ExtendedAttributeSet if attributes exist, None otherwise
- set_field_validation(field: Field, validation_rules: ValidationAttribute) None[source]¶
Set validation rules for a field.
- Parameters:
field – The field to set validation for
validation_rules – Validation attribute with rules
- get_field_validation(field: Field) ValidationAttribute | None[source]¶
Get validation rules for a field.
- Parameters:
field – The field to get validation for
- Returns:
ValidationAttribute if set, None otherwise
- validate_field_input(field: Field, input_text: str) Tuple[bool, str | None][source]¶
Validate input against field’s validation rules.
- Parameters:
field – The field to validate input for
input_text – The input text to validate
- Returns:
Tuple of (is_valid, error_message)
- select_light_pen(row: int, col: int) int | None[source]¶
Simulate a light pen selection at the given row and col.
If the field at the given position is light-pen selectable, this method will mark the field as selected, store the selection position, and return the light pen AID. Otherwise, it returns None.
EBCDIC¶
EBCDIC to ASCII translation utilities for 3270 emulation. Based on IBM Code Page 037.
- class pure3270.emulation.ebcdic.EmulationEncoder[source]¶
Bases:
objectUtility class for EBCDIC encoding/decoding in 3270 emulation.
The class exposes encode(text) -> bytes and decode(data) -> str which use IBM Code Page 037 (CP037) for conversions.
- static decode(data: bytes) str[source]¶
Decode EBCDIC bytes to a printable ASCII string.
Uses CP037 decoding followed by mapping/normalization to ensure the returned string contains only printable ASCII characters (plus newline/carriage/tab). This hides raw EBCDIC/box-graphics from the caller and provides readable approximations for line-drawing chars.
- pure3270.emulation.ebcdic.translate_ebcdic_to_ascii(data: bytes, codepage: str = 'cp037') str[source]¶
Translate raw EBCDIC bytes to ASCII string matching p3270 behavior.
Decode using specified EBCDIC codepage and return raw decoded string like p3270 does, without heavy filtering or normalization.
- pure3270.emulation.ebcdic.translate_ascii_to_ebcdic(text: str, codepage: str = 'cp037') bytes[source]¶
Translate an ASCII/Unicode string to EBCDIC bytes using specified codepage.
- pure3270.emulation.ebcdic.get_p3270_version() str | None[source]¶
Get p3270 version for patching.
Returns the installed p3270 package version string or None.
- pure3270.emulation.ebcdic.encode_field_attribute(attr: int) int[source]¶
Encode 3270 field attribute to EBCDIC.
Current implementation treats attributes as direct values and returns the input unchanged. This is a placeholder for future mapping logic.
- class pure3270.emulation.ebcdic.EBCDICCodec(codepage: str = 'cp037', compat: str | None = None)[source]¶
Bases:
objectBackwards-compatible EBCDIC codec used by tests.
This class provides a simple mapping-based encode/decode API that matches historical project tests: methods return tuples (value, length) and unknown characters are encoded as 0x7A and decoded as ‘z’.
The implementation uses configurable EBCDIC codec for deriving a base mapping where possible but intentionally restricts to reverse mapping to a conservative set (uppercase letters, digits and space) so that punctuation and other characters fall back to as ‘unknown’ mapping.
- decode(data: bytes) tuple[str, int][source]¶
Optimized decode with pre-computed character processing.
- encode(text: str | bytes) Tuple[bytes, int][source]¶
Encode text to EBCDIC bytes, returning (bytes, length).
Accepts either str or bytes. If bytes are provided they are interpreted as latin-1 and decoded before encoding so callers that pass raw bytes won’t raise. Prefers full CP037 mapping, falling back to conservative mapping only on failure. Characters not present in the conservative reverse mapping are encoded as 0x7A.
Protocol Modules¶
TN3270 Handler¶
TN3270 protocol handler for pure3270. Handles negotiation, data sending/receiving, and protocol specifics.
- class pure3270.protocol.tn3270_handler.HandlerState[source]¶
Bases:
objectTN3270Handler state constants.
- DISCONNECTED = 'DISCONNECTED'¶
- CONNECTING = 'CONNECTING'¶
- NEGOTIATING = 'NEGOTIATING'¶
- CONNECTED = 'CONNECTED'¶
- ASCII_MODE = 'ASCII_MODE'¶
- TN3270_MODE = 'TN3270_MODE'¶
- ERROR = 'ERROR'¶
- RECOVERING = 'RECOVERING'¶
- CLOSING = 'CLOSING'¶
- exception pure3270.protocol.tn3270_handler.StateTransitionError[source]¶
Bases:
ExceptionRaised when an invalid state transition is attempted.
- exception pure3270.protocol.tn3270_handler.StateValidationError[source]¶
Bases:
ExceptionRaised when state validation fails.
- class pure3270.protocol.tn3270_handler.TN3270Handler(reader: StreamReader | None, writer: StreamWriter | None, screen_buffer: ScreenBuffer | None = None, ssl_context: SSLContext | None = None, host: str = 'localhost', port: int = 23, is_printer_session: bool = False, force_mode: str | None = None, allow_fallback: bool = True, recorder: TraceRecorder | None = None, terminal_type: str = 'IBM-3278-2')[source]¶
Bases:
objectHandler for TN3270 protocol over Telnet. Manages stream I/O, negotiation, and data parsing for 3270 emulation.
- __init__(reader: StreamReader | None, writer: StreamWriter | None, screen_buffer: ScreenBuffer | None = None, ssl_context: SSLContext | None = None, host: str = 'localhost', port: int = 23, is_printer_session: bool = False, force_mode: str | None = None, allow_fallback: bool = True, recorder: TraceRecorder | None = None, terminal_type: str = 'IBM-3278-2')[source]¶
- ssl_context: SSLContext | None¶
- screen_buffer: ScreenBuffer¶
- printer_buffer: PrinterBuffer | None¶
- negotiator: Negotiator¶
- parser: DataStreamParser¶
- enable_sequence_sync(enable: bool = True) None[source]¶
Enable or disable sequence number synchronization.
- set_sequence_window(window_size: int) None[source]¶
Set the sequence number validation window size with enhanced bounds.
- async negotiate_addressing_mode() None[source]¶
Perform addressing mode negotiation during TN3270E session establishment.
This method coordinates with the addressing negotiator to determine the appropriate addressing mode based on client capabilities and server responses.
- get_negotiated_addressing_mode() AddressingMode | None[source]¶
Get the currently negotiated addressing mode.
- Returns:
The negotiated addressing mode, or None if not yet negotiated
- async handle_bind_image(bind_image_data: bytes) None[source]¶
Handle BIND-IMAGE structured field and update addressing mode negotiation.
- Parameters:
bind_image_data – Raw BIND-IMAGE structured field data
- async validate_addressing_mode_transition(from_mode: AddressingMode | None, to_mode: AddressingMode) bool[source]¶
Validate if an addressing mode transition is allowed.
- Parameters:
from_mode – Current addressing mode
to_mode – Proposed new addressing mode
- Returns:
True if transition is valid, False otherwise
- async transition_addressing_mode(new_mode: AddressingMode, reason: str = 'mode transition') None[source]¶
Perform a thread-safe addressing mode transition.
- Parameters:
new_mode – The new addressing mode to transition to
reason – Reason for the transition
- Raises:
ValueError – If transition is not allowed or fails
- get_addressing_negotiation_summary() Dict[str, Any][source]¶
Get a summary of the addressing mode negotiation process.
- Returns:
Dictionary containing negotiation details
- configure_timing_profile(profile: str = 'standard') None[source]¶
Configure x3270-compatible timing profile for negotiation.
- add_state_change_callback(state: str, callback: Callable[[str, str, str], Awaitable[None]]) None[source]¶
Add a callback for state changes (expects 3 arguments).
Accepts regular callables, coroutine functions, MagicMocks, and objects with __call__. Signature is validated best-effort; if introspection is unavailable, the callback is accepted.
- remove_state_change_callback(state: str, callback: Callable[[str, str, str], Awaitable[None]]) None[source]¶
Remove a state change callback (expects 3 arguments).
- add_state_entry_callback(state: str, callback: Callable[[str], Awaitable[None]]) None[source]¶
Add a callback for when entering a state (expects 1 argument).
Accepts regular callables, coroutine functions, MagicMocks, and objects with __call__. Signature validation is best-effort; non-introspectable callables are accepted.
- add_state_exit_callback(state: str, callback: Callable[[str], Awaitable[None]]) None[source]¶
Add a callback for when exiting a state (expects 1 argument).
Accepts regular callables, coroutine functions, MagicMocks, and objects with __call__. Signature validation is best-effort; non-introspectable callables are accepted.
- wait_for_state(state: str, timeout: float = 30.0) Event[source]¶
Get an event that will be set when entering the specified state.
- async connect(host: str | None = None, port: int | None = None, ssl_context: SSLContext | None = None) None[source]¶
Connect the handler with enhanced state management and x3270 timing.
- set_ascii_mode() None[source]¶
Set the handler to ASCII mode fallback.
Disables EBCDIC processing and sets screen buffer to ASCII mode.
- async send_data(data: bytes) None[source]¶
Send data over the connection.
- Parameters:
data – Bytes to send.
- Raises:
ProtocolError – If writer is None or send fails.
- async receive_data(timeout: float = 5.0) bytes[source]¶
Receive data with timeout.
- Parameters:
timeout – Receive timeout in seconds.
- Returns:
Received bytes.
- Raises:
asyncio.TimeoutError – If timeout exceeded.
ProtocolError – If reader is None.
- async send_scs_data(scs_data: bytes) None[source]¶
Send SCS character data for printer sessions.
- Parameters:
scs_data – SCS character data to send
- Raises:
ProtocolError – If not connected or not a printer session
- async send_printer_status_sf(status_code: int) None[source]¶
Send a Printer Status Structured Field to the host.
- Parameters:
status_code – The status code to send (e.g., DEVICE_END, INTERVENTION_REQUIRED).
- Raises:
ProtocolError – If not connected or writer is None.
- async send_sysreq_command(command_code: int) None[source]¶
Send a SYSREQ command to the host.
Per RFC 2355 10.5.2: - When in suspended mode, second SYSREQ key press exits suspended mode - SYSREQ with ATTN code while suspended sends LUSTAT and exits suspended mode
- Parameters:
command_code – The byte code representing the SYSREQ command.
- async send_break() None[source]¶
Send a Telnet BREAK command (IAC BRK) to the host.
- Raises:
ProtocolError – If not connected or writer is None.
- async send_soh_message(status_code: int) None[source]¶
Send an SOH (Start of Header) message for printer status to the host.
- Parameters:
status_code – The status code to send (e.g., SOH_SUCCESS, SOH_DEVICE_END).
- Raises:
ProtocolError – If not connected or writer is None.
- async send_print_eoj() None[source]¶
Send PRINT-EOJ (End of Job) command for printer sessions.
- Raises:
ProtocolError – If not connected or not a printer session
- set_negotiated_tn3270e(value: bool, propagate: bool = True) None[source]¶
Set negotiated_tn3270e flag on handler and optionally propagate to negotiator.
- Parameters:
value – New negotiated flag value
propagate – When True, update negotiator as well (default True). When False, the call is assumed to originate from the negotiator and should not re-propagate.
- validate_negotiation_completion() bool[source]¶
Validate that negotiation is complete before processing screen data.
This method checks if TN3270E negotiation has completed successfully and is ready for screen data processing. Integrates with the negotiator’s validation method and adds additional handler-level checks.
For connected-3270 traces, we are more lenient since the server may not perform full TN3270E negotiation.
- Returns:
True if negotiation is complete and ready for screen processing, False otherwise.
Data Stream¶
Data stream parser and sender for 3270 protocol.
- class pure3270.protocol.data_stream.DataStreamParser(screen_buffer: ScreenBuffer, printer_buffer: PrinterBuffer | None = None, negotiator: Negotiator | None = None, addressing_mode: AddressingMode = AddressingMode.MODE_12_BIT)[source]¶
Bases:
object- parse_light_pen_aid(data: bytes) None[source]¶
Minimal parsing support for light-pen AID sequences used by tests. Expected sequence for light-pen AID is:
[LIGHT_PEN_AID, high6bits, low6bits]
where the two following bytes contain 6-bit high/low parts of the 12-bit screen address: address = (high & 0x3F) << 6 | (low & 0x3F) and address maps to row,col using screen.columns.
- __init__(screen_buffer: ScreenBuffer, printer_buffer: PrinterBuffer | None = None, negotiator: Negotiator | None = None, addressing_mode: AddressingMode = AddressingMode.MODE_12_BIT) None[source]¶
Initialize the DataStreamParser with enhanced validation and buffer protection.
- Parameters:
screen_buffer – ScreenBuffer to update.
printer_buffer – PrinterBuffer to update for printer sessions.
negotiator – Negotiator instance for communicating dimension updates.
addressing_mode – Addressing mode for parsing operations.
- screen: ScreenBuffer¶
- printer: PrinterBuffer | None¶
- negotiator: Negotiator | None¶
- addressing_mode: AddressingMode¶
- sf_validator: StructuredFieldValidator¶
- parse(data: bytes, data_type: int = 0) Any[source]¶
Parse 3270 data stream or other data types with enhanced validation and buffer protection.
- build_query_reply_sf(query_type: int, data: bytes = b'') bytes[source]¶
Build a Query Reply structured field (type byte + optional data).
- class pure3270.protocol.data_stream.DataStreamSender[source]¶
Bases:
objectData stream sender for building 3270 protocol data streams.
- build_input_stream(modified_fields: List[Tuple[int, bytes]], aid: int, cols: int) bytes[source]¶
Build input stream from modified fields.
- build_printer_status_sf(status_code: int) bytes[source]¶
Build printer status structured field for SNA SOH compliance.
This method constructs a Structured Field (SF) for printer status reporting. For SNA SOH integration, the SF can be wrapped in SOH (0x01) when sent in SCS data streams.
- Parameters:
status_code – The printer status code (e.g., 0x00 for success, 0x40 for device end, 0x80 for intervention required).
- Returns:
Bytes representing the SF for printer status.
Note
Common status codes: - 0x00: Success/Ready - 0x40: Device End - 0x80: Intervention Required - 0x81: Power Off/On - 0x82: Not Ready - 0x83: Intervention Required (specific)
- get_structured_field_info() Dict[str, Any][source]¶
Get information about structured field processing capabilities.
- class pure3270.protocol.data_stream.SnaResponse(response_type: int, flags: int | None = None, sense_code: int | None = None, data: object | None = None)[source]¶
Bases:
objectRepresents a parsed SNA response.
- class pure3270.protocol.data_stream.BindImage(rows: int | None = None, cols: int | None = None, query_reply_ids: List[int] | None = None, model: int | None = None, flags: int | None = None, session_parameters: Dict[str, Any] | None = None)[source]¶
Bases:
objectRepresents a parsed BIND-IMAGE Structured Field with enhanced validation.
Negotiator¶
Negotiator for TN3270 protocol specifics. Handles Telnet negotiation and TN3270E subnegotiation.
- class pure3270.protocol.negotiator.SnaSessionState(value)[source]¶
Bases:
EnumRepresents the current state of the SNA session.
- NORMAL = 'NORMAL'¶
- ERROR = 'ERROR'¶
- PENDING_RECOVERY = 'PENDING_RECOVERY'¶
- SESSION_DOWN = 'SESSION_DOWN'¶
- LU_BUSY = 'LU_BUSY'¶
- INVALID_SEQUENCE = 'INVALID_SEQUENCE'¶
- STATE_ERROR = 'STATE_ERROR'¶
- exception pure3270.protocol.negotiator.SnaStateTransitionError[source]¶
Bases:
ExceptionRaised when an invalid SNA state transition is attempted.
- class pure3270.protocol.negotiator.Negotiator(writer: Any | None, parser: DataStreamParser | None = None, screen_buffer: ScreenBuffer | None = None, handler: TN3270Handler | None = None, is_printer_session: bool = False, force_mode: str | None = None, allow_fallback: bool = True, recorder: TraceRecorder | None = None, terminal_type: str = 'IBM-3278-2', negotiation_mode: str = 'strict')[source]¶
Bases:
object- __init__(writer: Any | None, parser: DataStreamParser | None = None, screen_buffer: ScreenBuffer | None = None, handler: TN3270Handler | None = None, is_printer_session: bool = False, force_mode: str | None = None, allow_fallback: bool = True, recorder: TraceRecorder | None = None, terminal_type: str = 'IBM-3278-2', negotiation_mode: str = 'strict')[source]¶
Initialize the Negotiator.
_timing_metrics: Dict[str, Any] def __init__(
writer: StreamWriter for sending commands. parser: DataStreamParser for parsing responses. screen_buffer: ScreenBuffer to update during negotiation. handler: TN3270Handler instance for accessing reader methods. is_printer_session: True if this is a printer session.
- set_negotiated_tn3270e(value: bool) None[source]¶
Public API: set negotiated_tn3270e flag and propagate state changes.
- validate_negotiation_completion() bool[source]¶
Validate that the negotiation has completed sufficiently to process TN3270/TN3270E screen data.
This is a conservative check used by the TN3270 handler to decide whether it is safe to treat incoming data as 3270 data rather than early ASCII/VT100 streams. It must be synchronous to integrate with the handler’s fast-path calls.
- Returns:
True if negotiation is complete, False otherwise.
- validate_negotiation_completion_with_details() Dict[str, Any][source]¶
Return a dictionary with negotiation validation details for diagnostics.
- update_printer_status(status_code: int) None[source]¶
Update cached printer status and signal any waiters.
This mirrors legacy negotiator behavior that exposed a simple status update hook used by printer session paths.
- infer_tn3270e_from_trace(trace: bytes) bool[source]¶
Infer TN3270E negotiation success from raw Telnet negotiation bytes.
This mirrors the temporary heuristic previously implemented in the handler. We keep it here so that test fixtures can rely on a single canonical implementation and the handler stays slim.
- Rules:
If IAC WONT TN3270E (FF FC 24) or IAC DONT TN3270E (FF FE 24) appears => failure (False).
Else if IAC WILL EOR (FF FB 19) appears => success (True).
Otherwise => False.
The heuristic is intentionally conservative; explicit refusal always wins over implied success.
- async negotiate() None[source]¶
Perform initial Telnet negotiation with x3270-compatible timing.
Sends WILL TERMINAL-TYPE and DO TERMINAL-TYPE during initial negotiation, then waits for responses with precise timing that matches x3270’s negotiation patterns.
- Raises:
NegotiationError – If negotiation fails after all retries.
- set_ascii_mode() None[source]¶
Set to ASCII mode fallback, matching s3270 behavior.
Disables EBCDIC processing and enables ASCII/VT100 terminal emulation.
- async handle_iac_command(command: int, option: int) None[source]¶
Handle Telnet IAC (Interpret As Command) commands.
- Parameters:
command – The IAC command (DO, DONT, WILL, WONT).
option – The Telnet option number.
- is_printer_session_active() bool[source]¶
Check if this is a printer session.
- Returns:
True if printer session.
- Return type:
- property is_bind_image_active: bool¶
Return True when BIND-IMAGE function bit is active, or override for tests.
- async handle_subnegotiation(option: int, sub_payload: bytes) None[source]¶
Handle Telnet subnegotiation for non-TN3270E options.
- Parameters:
option – The Telnet option number.
sub_payload – The subnegotiation payload.
- property current_sna_session_state: SnaSessionState¶
Get the current SNA session state.
- handle_bind_image(bind_image: BindImage) None[source]¶
Handle BIND-IMAGE structured field.
- Parameters:
bind_image – The BIND-IMAGE to handle.
- async negotiate_addressing_mode() None[source]¶
Perform addressing mode negotiation during TN3270E session establishment.
This method coordinates with the addressing negotiator to determine the appropriate addressing mode based on client capabilities and server responses.
- get_negotiated_addressing_mode() AddressingMode | None[source]¶
Get the currently negotiated addressing mode.
- Returns:
The negotiated addressing mode, or None if not yet negotiated
- async handle_bind_image_addressing(bind_image_data: bytes) None[source]¶
Handle BIND-IMAGE structured field and update addressing mode negotiation.
- Parameters:
bind_image_data – Raw BIND-IMAGE structured field data
- async validate_addressing_mode_transition(from_mode: AddressingMode | None, to_mode: AddressingMode) bool[source]¶
Validate if an addressing mode transition is allowed.
- Parameters:
from_mode – Current addressing mode (None if not set)
to_mode – Proposed new addressing mode
- Returns:
True if transition is valid, False otherwise
- async transition_addressing_mode(new_mode: AddressingMode, reason: str = 'mode transition') None[source]¶
Perform a thread-safe addressing mode transition.
- Parameters:
new_mode – The new addressing mode to transition to
reason – Reason for the transition
- Raises:
ValueError – If transition is not allowed or fails
SSL Wrapper¶
SSL/TLS wrapper for secure TN3270 connections using stdlib ssl module.
- exception pure3270.protocol.ssl_wrapper.SSLError[source]¶
Bases:
ExceptionError during SSL operations.
- class pure3270.protocol.ssl_wrapper.SSLWrapper(verify: bool = True, cafile: str | None = None, capath: str | None = None)[source]¶
Bases:
objectLayers SSL/TLS on top of asyncio connections using Python’s ssl module.
- __init__(verify: bool = True, cafile: str | None = None, capath: str | None = None)[source]¶
Initialize the SSLWrapper.
- Parameters:
verify – Whether to verify the server’s certificate.
cafile – Path to CA certificate file.
capath – Path to CA certificates directory.
- create_context() SSLContext[source]¶
Create an SSLContext for secure connections.
This implementation matches the expectations of our tests: - Build context with ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - When verify=True: check_hostname=True and verify_mode=CERT_REQUIRED - Enforce minimum TLS 1.2 - Configure cipher suite to “HIGH:!aNULL:!MD5”
- Returns:
Configured SSLContext.
- Raises:
SSLError – If context creation fails.
- wrap_connection(telnet_connection: Any) Any[source]¶
Wrap an existing telnet connection with SSL with x3270-compatible fallback mechanisms.
- Parameters:
telnet_connection – The telnet connection object (e.g., from asyncio.open_connection).
- Returns:
Wrapped connection.
Note: This is a stub; asyncio.open_connection handles SSL natively via ssl parameter.
- create_fallback_context() SSLContext[source]¶
Create a fallback SSL context for legacy server compatibility.
- Returns:
Fallback SSLContext with relaxed security for compatibility.
- Raises:
SSLError – If context creation fails.
- test_ssl_compatibility(hostname: str, port: int) Dict[str, Any][source]¶
Test SSL compatibility with a target server.
- Parameters:
hostname – Target hostname
port – Target port
- Returns:
Compatibility test results
- get_context() SSLContext[source]¶
Get the SSLContext (create if not exists).
Printer Sessions¶
High-level printer session classes for TN3270E printer LU support.
Session management for pure3270, handling synchronous and asynchronous 3270 connections.
- exception pure3270.session.SessionError(message: str, context: Dict[str, Any] | None = None)[source]¶
Bases:
ExceptionBase exception for session-related errors.
When context is provided, include key details in the string representation so tests can assert on them without reaching into attributes.
- exception pure3270.session.ConnectionError(message: str, context: Dict[str, Any] | None = None)[source]¶
Bases:
SessionErrorRaised when connection fails.
- class pure3270.session.Session(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2')[source]¶
Bases:
objectSynchronous wrapper for AsyncSession.
This class provides a synchronous interface to the asynchronous 3270 session. All methods use asyncio.run() to execute async operations.
- __init__(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2') None[source]¶
Initialize a synchronous session with a dedicated thread and event loop.
- connect(host: str | None = None, port: int | None = None, ssl_context: Any | None = None) None[source]¶
Connect to the 3270 host synchronously.
- Parameters:
host – Optional host override.
port – Optional port override (default 23).
ssl_context – Optional SSL context override.
- Raises:
ConnectionError – If connection fails.
- send(data: bytes) None[source]¶
Send data to the session.
- Parameters:
data – Bytes to send.
- Raises:
SessionError – If send fails.
- read(timeout: float = 5.0) bytes[source]¶
Read data from the session.
- Parameters:
timeout – Read timeout in seconds.
- Returns:
Received bytes.
- Raises:
SessionError – If read fails.
- property screen_buffer: ScreenBuffer¶
Expose screen buffer for sync Session tests.
- property tn3270e_mode: bool¶
Check if session is in TN3270E mode.
Preference order: 1) Async session’s tn3270 mode flag when True 2) Handler’s negotiated_tn3270e flag as a fallback
- ascii(data: bytes) str[source]¶
Convert EBCDIC data to ASCII text (s3270 Ascii() action).
- Parameters:
data – EBCDIC bytes to convert.
- Returns:
ASCII string representation.
- ebcdic(text: str) bytes[source]¶
Convert ASCII text to EBCDIC data (s3270 Ebcdic() action).
- Parameters:
text – ASCII text to convert.
- Returns:
EBCDIC bytes representation.
- ascii1(byte_val: int) str[source]¶
Convert a single EBCDIC byte to ASCII character.
This is a pure conversion utility and does not require a live session.
- ebcdic1(char: str) int[source]¶
Convert a single ASCII character to EBCDIC byte.
This is a pure conversion utility and does not require a live session.
- ascii_field(field_index: int) str[source]¶
Convert field content to ASCII text (s3270 AsciiField() action).
- Parameters:
field_index – Index of field to convert.
- Returns:
ASCII string representation of field content.
- cursor_select() None[source]¶
Select field at cursor (s3270 CursorSelect() action).
- Raises:
SessionError – If not connected.
- delete_field() None[source]¶
Delete field at cursor (s3270 DeleteField() action).
- Raises:
SessionError – If not connected.
- circum_not() None[source]¶
Toggle circumvention of field protection (s3270 CircumNot() action).
- Raises:
SessionError – If not connected.
- script(commands: str) None[source]¶
Execute script (s3270 Script() action).
- Parameters:
commands – Script commands.
- Raises:
SessionError – If not connected.
- query(query_type: str = 'All') str[source]¶
Query session information synchronously.
- Supported query types (s3270 protocol parity):
All: Summary information
CodePage: Host code page
ConnectionState: Connection state
Cursor: Cursor position
Model: 3270 model information
ScreenCurSize: Current screen dimensions
Tn3270eOptions: Active TN3270E functions
TelnetHostOptions: Host TELNET options
TelnetMyOptions: Client TELNET options
And 30+ more query types…
- move_cursor1(row: int, col: int) None[source]¶
Move cursor to specified position (s3270 MoveCursor1 action).
- class pure3270.session.AsyncSession(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2', is_printer_session: bool = False)[source]¶
Bases:
objectAsynchronous 3270 session handler.
This class provides an asynchronous interface to the 3270 session. All operations are async and use asyncio for non-blocking I/O.
- AID_MAP: Dict[str, int] = {'Attn': 241, 'BackSpace': 248, 'CLEAR': 109, 'Dup': 245, 'Enter': 125, 'PA(1)': 108, 'PA(2)': 110, 'PA(3)': 107, 'PF(1)': 241, 'PF(10)': 122, 'PF(11)': 123, 'PF(12)': 124, 'PF(13)': 193, 'PF(14)': 194, 'PF(15)': 195, 'PF(16)': 196, 'PF(17)': 197, 'PF(18)': 198, 'PF(19)': 199, 'PF(2)': 242, 'PF(20)': 200, 'PF(21)': 201, 'PF(22)': 74, 'PF(23)': 75, 'PF(24)': 76, 'PF(3)': 243, 'PF(4)': 244, 'PF(5)': 245, 'PF(6)': 246, 'PF(7)': 247, 'PF(8)': 248, 'PF(9)': 249, 'RESET': 106, 'SysReq': 240, 'TEST': 17, 'Test': 17}¶
- __init__(host: str | None = None, port: int = 23, ssl_context: Any | None = None, force_mode: str | None = None, allow_fallback: bool = True, enable_trace: bool = False, terminal_type: str = 'IBM-3278-2', is_printer_session: bool = False) None[source]¶
Initialize the AsyncSession.
- Parameters:
host – Host to connect to.
port – Port to connect to.
ssl_context – SSL context for secure connections.
force_mode – Force specific TN3270 mode.
allow_fallback – Allow fallback to TN3270 if TN3270E fails.
enable_trace – Enable tracing.
terminal_type – Terminal model type.
is_printer_session – True if this is a printer session.
- property screen_buffer: ScreenBuffer¶
Get the screen buffer.
- property screen: ScreenBuffer¶
Get the screen buffer (alias for screen_buffer).
- property handler: TN3270Handler | None¶
Get the underlying TN3270 handler (may be None if not connected).
- async connect(host: str | None = None, port: int | None = None, ssl_context: Any | None = None) None[source]¶
Connect to the 3270 host asynchronously.
- async receive_data(timeout: float = 5.0) bytes[source]¶
Receive data from the session (alias for read).
- managed() AsyncIterator[AsyncSession][source]¶
Provide a managed async context that guarantees close() on exit.
- async script(commands: str) None[source]¶
Execute script command(s).
Supports both simple method names and function-style commands like: - Simple: “connect”, “disconnect” - With args: “String(test)”, “MoveCursor(5,10)”
- async set_option(option: str, value: str) None[source]¶
Set option (placeholder for future functionality).
- async delete() None[source]¶
Delete character at cursor by shifting remainder left and clearing last.
- async send_file(local_path: str, remote_name: str) None[source]¶
Send a file to the host using IND$FILE protocol.
- async receive_file(remote_name: str, local_path: str) None[source]¶
Receive a file from the host using IND$FILE protocol.
Printer Protocol¶
Low-level printer protocol implementation.
Advanced printer session support for TN3270E protocol with comprehensive SCS control codes.
- class pure3270.protocol.printer.PrinterJob(job_id: str = '', max_data_size: int = 1048576)[source]¶
Bases:
objectRepresents a printer job in a TN3270E printer session with advanced features.
- class pure3270.protocol.printer.PrinterSession[source]¶
Bases:
objectAdvanced TN3270E printer session handler with comprehensive SCS support.
- start_new_job(job_id: str = '') PrinterJob[source]¶
Start a new printer job.
- add_scs_data(data: bytes, holding_lock: bool = False) None[source]¶
Add SCS character data to the current job.
- Parameters:
data – SCS data to add
holding_lock – True if caller already holds self.lock (internal use only)
- get_current_job() PrinterJob | None[source]¶
Get the current active job.
- get_completed_jobs() List[PrinterJob][source]¶
Get the list of completed jobs.
- handle_scs_control_code(scs_code: int) None[source]¶
Handle SCS control codes with comprehensive support.
- process_tn3270e_message(header: TN3270EHeader, data: bytes) None[source]¶
Process a TN3270E message for printer session with comprehensive support.
TN3270E Header¶
TN3270E message header structure for pure3270.
- class pure3270.protocol.tn3270e_header.TN3270EHeader(data_type: int = 0, request_flag: int = 0, response_flag: int = 0, seq_number: int = 0)[source]¶
Bases:
objectTN3270E Message Header Structure (RFC 2355 Section 3).
The TN3270E header is a 5-byte structure with the following fields:
Byte 0: DATA-TYPE Byte 1: REQUEST-FLAG Byte 2: RESPONSE-FLAG Byte 3-4: SEQ-NUMBER (16-bit big-endian)
Extended for addressing mode negotiation: - REQUEST-FLAG bit 7: Extended addressing capability (14-bit support) - RESPONSE-FLAG bit 7: Extended addressing negotiated
- REQUEST_EXTENDED_ADDRESSING = 128¶
- RESPONSE_EXTENDED_ADDRESSING = 128¶
- __init__(data_type: int = 0, request_flag: int = 0, response_flag: int = 0, seq_number: int = 0)[source]¶
Initialize a TN3270E header.
- Parameters:
data_type – Type of data (TN3270_DATA, SCS_DATA, etc.)
request_flag – Request flags
response_flag – Response flags
seq_number – Sequence number (0-65535)
- classmethod from_bytes(data: bytes) TN3270EHeader | None[source]¶
Parse a TN3270E header from bytes with enhanced malformed data handling.
- Parameters:
data – 5 bytes containing the TN3270E header
- Returns:
TN3270EHeader instance or None if parsing fails
- to_bytes() bytes[source]¶
Convert the header to bytes.
- Returns:
5 bytes representing the TN3270E header
- is_no_response() bool[source]¶
Check if this is a no-response flag (0x00).
Per RFC 2355, NO-RESPONSE (0x00) means the sender does not expect the receiver to respond either positively or negatively.
- is_negative_response() bool[source]¶
Check if this is a negative response (error response per RFC 2355).
Note: RFC 2355 doesn’t have a separate ‘negative response’ flag. ERROR-RESPONSE (0x01) means ‘respond only if error’. Negative responses are indicated by ERROR-RESPONSE with sense data.
- has_extended_addressing_request() bool[source]¶
Check if this header requests extended addressing capability.
- has_extended_addressing_response() bool[source]¶
Check if this header indicates extended addressing was negotiated.
- set_extended_addressing_request(enabled: bool = True) None[source]¶
Set or clear the extended addressing request flag.
- set_extended_addressing_response(enabled: bool = True) None[source]¶
Set or clear the extended addressing response flag.
- handle_negative_response(data: bytes) None[source]¶
Handle negative response by parsing the code and raising ProtocolError with details.
- Parameters:
data – Bytes following the header, starting with the negative code byte.
- Raises:
ProtocolError – With details of the negative response code and sense if applicable.
- class pure3270.protocol.tn3270e_header.MalformedDataHandler[source]¶
Bases:
object- malformed_data_log: list[dict[str, object]]¶
Handles malformed TN3270E data and provides recovery mechanisms.
- handle_malformed_header(data: bytes, context: str = '') TN3270EHeader | None[source]¶
Attempt to recover from malformed TN3270E headers.
- Parameters:
data – Raw bytes that may contain a malformed header
context – Context information for logging
- Returns:
TN3270EHeader instance if recovery successful, None otherwise
Utils¶
- pure3270.protocol.utils.TN3270E_QUERY = 15¶
Utility functions for TN3270/TN3270E protocol handling.
Typing notes: - Writer parameters are annotated as Optional[asyncio.StreamWriter] to reflect possibility of absent writer during teardown. - _schedule_if_awaitable centralizes best-effort handling of AsyncMock.write returning an awaitable to avoid repeated inline inspection logic.
- class pure3270.protocol.utils.TerminalCapabilities(screen_size: Tuple[int, int], color_support: bool, extended_attributes: bool, programmed_symbols: bool, extended_highlighting: bool, light_pen_support: bool, magnetic_slot_reader: bool, operator_information_area: bool, max_alternate_screen_size: Tuple[int, int] | None = None, character_sets: List[str] | None = None)[source]¶
Bases:
objectDefines the capabilities and characteristics of a 3270 terminal model.
Based on IBM 3270 Data Stream Programmer’s Reference and GA23-0059 documentation.
- __init__(screen_size: Tuple[int, int], color_support: bool, extended_attributes: bool, programmed_symbols: bool, extended_highlighting: bool, light_pen_support: bool, magnetic_slot_reader: bool, operator_information_area: bool, max_alternate_screen_size: Tuple[int, int] | None = None, character_sets: List[str] | None = None) None¶
- pure3270.protocol.utils.get_supported_terminal_models() List[str][source]¶
Get list of all supported terminal model names.
- pure3270.protocol.utils.is_valid_terminal_model(model: str) bool[source]¶
Check if a terminal model is supported.
- pure3270.protocol.utils.get_terminal_capabilities(model: str) TerminalCapabilities | None[source]¶
Get capabilities for a specific terminal model.
- pure3270.protocol.utils.get_screen_size(model: str) Tuple[int, int][source]¶
Get screen dimensions for a terminal model.
- pure3270.protocol.utils.send_iac(writer: StreamWriter | None, command: bytes) None[source]¶
Send an IAC command to the writer.
Ensures the IAC (0xFF) prefix is present exactly once. If the provided command already begins with IAC, it will not be duplicated.
- pure3270.protocol.utils.send_subnegotiation(writer: StreamWriter | None, opt: bytes, data: bytes) None[source]¶
Send subnegotiation.
- Parameters:
writer – StreamWriter.
opt – Option byte.
data – Subnegotiation data.
- pure3270.protocol.utils.strip_telnet_iac(data: bytes, handle_eor_ga: bool = False, enable_logging: bool = False) bytes[source]¶
Strip Telnet IAC sequences from data.
- Parameters:
data – Raw bytes containing potential IAC sequences.
handle_eor_ga – If True, specifically handle EOR (0x19) and GA (0xf9) commands.
enable_logging – If True, log EOR/GA stripping.
- Returns:
Cleaned bytes without IAC sequences.
VT100 Parser¶
VT100 terminal emulator for pure3270 ASCII mode support.
This module provides VT100 escape sequence parsing to support ASCII terminal emulation as a fallback when TN3270 negotiation fails, matching s3270 behavior.
- class pure3270.protocol.vt100_parser.VT100ParserState[source]¶
Bases:
objectRepresents the recoverable state of a VT100 parser.
- save_from_parser(parser: VT100Parser) None[source]¶
Save current state from parser instance.
- restore_to_parser(parser: VT100Parser) None[source]¶
Restore state to parser instance.
- class pure3270.protocol.vt100_parser.VT100Parser(screen_buffer: ScreenBuffer)[source]¶
Bases:
objectVT100 escape sequence parser for ASCII terminal emulation.
- __init__(screen_buffer: ScreenBuffer) None[source]¶
Initialize VT100 parser.
- Parameters:
screen_buffer – ScreenBuffer instance to update with parsed content
Emulation Modules¶
Screen Buffer¶
Screen buffer management for 3270 emulation.
- class pure3270.emulation.screen_buffer.Field(start: Tuple[int, int], end: Tuple[int, int], protected: bool = False, numeric: bool = False, modified: bool = False, selected: bool = False, intensity: int = 0, color: int = 0, background: int = 0, validation: int = 0, outlining: int = 0, character_set: int = 0, sfe_highlight: int = 0, light_pen: int = 0, content: bytes | None = None, codepage: str = 'cp037')[source]¶
Bases:
objectA simple Field object that mirrors the previous namedtuple API with convenient defaults and helper methods used by tests.
It intentionally implements get_content, set_content, and _replace to be compatible with test expectations. content is stored as raw EBCDIC bytes; get_content/set_content use the EBCDICCodec by default but will fall back to EmulationEncoder when the codec isn’t present.
- __init__(start: Tuple[int, int], end: Tuple[int, int], protected: bool = False, numeric: bool = False, modified: bool = False, selected: bool = False, intensity: int = 0, color: int = 0, background: int = 0, validation: int = 0, outlining: int = 0, character_set: int = 0, sfe_highlight: int = 0, light_pen: int = 0, content: bytes | None = None, codepage: str = 'cp037') None[source]¶
- get_content(codec: EBCDICCodec | None = None) str[source]¶
Return decoded content as a Unicode string.
Accepts an optional codec for decoding; if not provided we use EBCDICCodec() when available, otherwise EmulationEncoder.
- class pure3270.emulation.screen_buffer.ScreenBuffer(rows: int = 24, cols: int = 80, init_value: int = 64, codepage: str = 'cp037')[source]¶
Bases:
BufferWriter- property ascii_buffer: str¶
Return the entire screen buffer as a multi-line ASCII string.
Tests expect exactly rows lines separated by newlines, regardless of trailing blank content. This method converts each row of the EBCDIC buffer to printable ASCII, masking non-printables to spaces, and joins all rows with newlines without trimming.
In ASCII mode, returns the buffer content directly as ASCII text.
- __init__(rows: int = 24, cols: int = 80, init_value: int = 64, codepage: str = 'cp037')[source]¶
Initialize the ScreenBuffer.
- Parameters:
rows – Number of rows (default 24).
cols – Number of columns (default 80).
init_value – Initial value for buffer (default 0x40 for space).
- set_ascii_mode(ascii_mode: bool) None[source]¶
Set ASCII mode for the screen buffer.
In ASCII mode, characters are stored as ASCII bytes directly. In EBCDIC mode (default), characters are converted to EBCDIC.
- Parameters:
ascii_mode – True for ASCII mode, False for EBCDIC mode
- get_field_content(field_index: int) str[source]¶
Return the content of the field at the given index as a decoded string.
- read_modified_fields() list[tuple[tuple[int, int], str]][source]¶
Return a list of tuples (position, content) for modified fields.
- set_position(row: int, col: int, wrap: bool = False, strict: bool = False) None[source]¶
Set cursor position with bounds checking or wrapping.
- Parameters:
row – Target row position
col – Target column position
wrap – If True, allow wrapping to next line; if False, check bounds
strict – If True, raise IndexError on out of bounds; if False, clamp values
- Raises:
IndexError – When strict=True and position is out of bounds
- write_char(ebcdic_byte: int, row: int | None = None, col: int | None = None, protected: bool = False, circumvent_protection: bool = False, mark_field_start: bool = False) None[source]¶
Write an EBCDIC character to the buffer at position.
- Parameters:
ebcdic_byte – EBCDIC byte value.
row – Row position.
col – Column position.
protected – Protection attribute to set.
circumvent_protection – If True, write even to protected fields.
mark_field_start – If True, mark this position as a field start.
- update_from_stream(data: bytes) None[source]¶
Update buffer from a 3270 data stream using proper DataStreamParser for accurate 3270 order handling.
For backward compatibility with tests expecting simple byte sequences, this method detects whether the data appears to be raw bytes (no 3270 orders) vs. actual 3270 data streams.
- Parameters:
data – Raw 3270 data stream bytes.
- to_text() str[source]¶
Convert screen buffer to Unicode text string.
- Returns:
Multi-line string representation.
- get_field_at_position(row: int, col: int) Field | None[source]¶
Get the field containing the given position, if any (optimized with caching).
- move_cursor_to_first_input_field() None[source]¶
Moves the cursor to the beginning of the first unprotected field with performance optimization.
- move_cursor_to_next_input_field() None[source]¶
Moves the cursor to the beginning of the next unprotected, non-skipped, non-autoskip field. Wraps around to the first field if no next field is found.
In ASCII mode, this also considers ASCII fields detected by VT100 parser.
- set_attribute(attr: int, row: int | None = None, col: int | None = None) None[source]¶
Set field attribute at specified or current position.
- repeat_attribute(attr: int, repeat: int) None[source]¶
Repeat attribute a specified number of times.
- set_extended_attribute_sfe(attr_type: int, attr_value: int) None[source]¶
Accumulate extended field attributes for the field at the current buffer address.
Important semantics: - Extended attributes (from SFE or SA) do NOT consume a display byte and
must NOT create a field-start marker on their own.
Only the base field attribute (set via SF or SFE type 0xC0) occupies a buffer position and should be recorded in _field_starts.
This method therefore ONLY updates the accumulated extended attributes and does not modify the display buffer or _field_starts.
- set_extended_attribute(row: int, col: int, attr_type: str, value: int) None[source]¶
Set an extended attribute at a specific position (used by tests and APIs).
This also records a field start at that position to align with field-start-driven detection.
- get_field_at(row: int, col: int) Field | None[source]¶
Alias for get_field_at_position for compatibility.
- get_extended_attributes_at(row: int, col: int) ExtendedAttributeSet | None[source]¶
Get extended attributes for a specific position.
- Parameters:
row – Row position
col – Column position
- Returns:
ExtendedAttributeSet if attributes exist, None otherwise
- set_field_validation(field: Field, validation_rules: ValidationAttribute) None[source]¶
Set validation rules for a field.
- Parameters:
field – The field to set validation for
validation_rules – Validation attribute with rules
- get_field_validation(field: Field) ValidationAttribute | None[source]¶
Get validation rules for a field.
- Parameters:
field – The field to get validation for
- Returns:
ValidationAttribute if set, None otherwise
- validate_field_input(field: Field, input_text: str) Tuple[bool, str | None][source]¶
Validate input against field’s validation rules.
- Parameters:
field – The field to validate input for
input_text – The input text to validate
- Returns:
Tuple of (is_valid, error_message)
- select_light_pen(row: int, col: int) int | None[source]¶
Simulate a light pen selection at the given row and col.
If the field at the given position is light-pen selectable, this method will mark the field as selected, store the selection position, and return the light pen AID. Otherwise, it returns None.
EBCDIC¶
EBCDIC to ASCII translation utilities for 3270 emulation. Based on IBM Code Page 037.
- class pure3270.emulation.ebcdic.EmulationEncoder[source]¶
Bases:
objectUtility class for EBCDIC encoding/decoding in 3270 emulation.
The class exposes encode(text) -> bytes and decode(data) -> str which use IBM Code Page 037 (CP037) for conversions.
- static decode(data: bytes) str[source]¶
Decode EBCDIC bytes to a printable ASCII string.
Uses CP037 decoding followed by mapping/normalization to ensure the returned string contains only printable ASCII characters (plus newline/carriage/tab). This hides raw EBCDIC/box-graphics from the caller and provides readable approximations for line-drawing chars.
- pure3270.emulation.ebcdic.translate_ebcdic_to_ascii(data: bytes, codepage: str = 'cp037') str[source]¶
Translate raw EBCDIC bytes to ASCII string matching p3270 behavior.
Decode using specified EBCDIC codepage and return raw decoded string like p3270 does, without heavy filtering or normalization.
- pure3270.emulation.ebcdic.translate_ascii_to_ebcdic(text: str, codepage: str = 'cp037') bytes[source]¶
Translate an ASCII/Unicode string to EBCDIC bytes using specified codepage.
- pure3270.emulation.ebcdic.get_p3270_version() str | None[source]¶
Get p3270 version for patching.
Returns the installed p3270 package version string or None.
- pure3270.emulation.ebcdic.encode_field_attribute(attr: int) int[source]¶
Encode 3270 field attribute to EBCDIC.
Current implementation treats attributes as direct values and returns the input unchanged. This is a placeholder for future mapping logic.
- class pure3270.emulation.ebcdic.EBCDICCodec(codepage: str = 'cp037', compat: str | None = None)[source]¶
Bases:
objectBackwards-compatible EBCDIC codec used by tests.
This class provides a simple mapping-based encode/decode API that matches historical project tests: methods return tuples (value, length) and unknown characters are encoded as 0x7A and decoded as ‘z’.
The implementation uses configurable EBCDIC codec for deriving a base mapping where possible but intentionally restricts to reverse mapping to a conservative set (uppercase letters, digits and space) so that punctuation and other characters fall back to as ‘unknown’ mapping.
- decode(data: bytes) tuple[str, int][source]¶
Optimized decode with pre-computed character processing.
- encode(text: str | bytes) Tuple[bytes, int][source]¶
Encode text to EBCDIC bytes, returning (bytes, length).
Accepts either str or bytes. If bytes are provided they are interpreted as latin-1 and decoded before encoding so callers that pass raw bytes won’t raise. Prefers full CP037 mapping, falling back to conservative mapping only on failure. Characters not present in the conservative reverse mapping are encoded as 0x7A.
Printer Buffer¶
Printer buffer and rendering logic for 3287 printer emulation.
- class pure3270.emulation.printer_buffer.PrinterBuffer(max_lines: int = 10000, auto_reset: bool = False)[source]¶
Bases:
BufferWriter- write_char(ebcdic_byte: int, row: int | None = None, col: int | None = None, protected: bool = False, circumvent_protection: bool = False) None[source]¶
Write an EBCDIC byte to the printer buffer.
The incoming value is an EBCDIC code point (0-255). Decode it to a Unicode character using the project’s EBCDICCodec rather than doing a direct chr() which treats the value as a Unicode codepoint and yields incorrect characters (e.g. 0xD9 -> ‘Ù’). Preserve simple positioning semantics used elsewhere in the codebase.
- set_attribute(attr: int, row: int | None = None, col: int | None = None) None[source]¶
Set attribute at position. Printer buffer does not support attributes.
- get_content() str[source]¶
Retrieve the buffer content as a cleaned, ASCII-safe string.
This method conservatively filters the rendered output to preserve printable ASCII and a few allowed control characters that are meaningful for printer output: newline, form-feed, and tab. It does NOT perform Unicode transliteration to avoid mangling decoded EBCDIC text.
- write_scs_data(data: bytes, parser_pos: int | None = None) None[source]¶
Processes incoming SCS data, parsing SCS commands and robustly translating EBCDIC to ASCII.
Notes: - Consume SOH (0x01) and the following status byte (when present) to avoid misalignment. - Decode contiguous runs of non-control bytes in bulk using EBCDICCodec.decode
instead of decoding one byte at a time to preserve any multi-byte mappings.
Preserve explicit handling for SCS control bytes: LF, CR, FF, HT.
Suppress screen-like content such as trace metadata, screen buffer dumps, and field commands.
- update_status(status_code: int) None[source]¶
Updates the printer’s internal status with the given status code.
- Parameters:
status_code – The status code (e.g., 0x00 success, 0x40 device end).
This method updates the internal status state and can trigger events or updates for status SF handling in TN3270E printer sessions.
Field Attributes¶
Advanced field attribute classes for 3270 emulation.
- class pure3270.emulation.field_attributes.AttributeType(value)[source]¶
Bases:
EnumEnumeration of supported extended attribute types.
- COLOR = 'color'¶
- HIGHLIGHT = 'highlight'¶
- VALIDATION = 'validation'¶
- OUTLINING = 'outlining'¶
- LIGHT_PEN = 'light_pen'¶
- BACKGROUND = 'background'¶
- CHARACTER_SET = 'character_set'¶
- class pure3270.emulation.field_attributes.ExtendedAttribute(value: int | str = 0)[source]¶
Bases:
ABCAbstract base class for extended field attributes.
Provides common functionality for all extended attribute types including validation, serialization, and thread-safe operations.
- __init__(value: int | str = 0) None[source]¶
Initialize extended attribute with value.
- Parameters:
value – The attribute value (int or string representation)
- Raises:
ValueError – If the value is invalid for this attribute type
- class pure3270.emulation.field_attributes.ExtendedAttributeSet[source]¶
Bases:
objectContainer for managing multiple extended attributes for a field position.
Provides thread-safe operations for setting, getting, and managing extended attributes with proper validation and error handling.
- get(attr_type: str, default: ExtendedAttribute | int | None = None) ExtendedAttribute | int | None[source]¶
Get an extended attribute by type, with optional default (test compatibility). Returns the raw value if the attribute is an object with a .value property.
- set_attribute(attr_type: str, attribute: Any) None[source]¶
Set an extended attribute.
- Parameters:
attr_type – The attribute type key
attribute – The attribute instance
- Raises:
TypeError – If attribute is not an ExtendedAttribute instance
- get_attribute(attr_type: str) Any[source]¶
Get an extended attribute by type.
- Parameters:
attr_type – The attribute type key
- Returns:
The attribute instance or None if not found
- remove_attribute(attr_type: str) bool[source]¶
Remove an extended attribute.
- Parameters:
attr_type – The attribute type key
- Returns:
True if attribute was removed, False if not found
- has_attribute(attr_type: str) bool[source]¶
Check if an attribute type is present.
- Parameters:
attr_type – The attribute type key
- Returns:
True if attribute exists
- get_all_attributes() Dict[str, ExtendedAttribute][source]¶
Get a copy of all attributes.
- Returns:
Dictionary of all attributes
- class pure3270.emulation.field_attributes.ColorAttribute(value: int | str = 0)[source]¶
Bases:
ExtendedAttributeColor attribute supporting base 16 and extended 256 color support.
Supports both standard 3270 colors (0-15) and extended colors (16-255) as defined in TN3270E specifications.
- BASE_COLORS = {0: 'neutral_black', 1: 'blue', 2: 'red', 3: 'pink', 4: 'green', 5: 'turquoise', 6: 'yellow', 7: 'neutral_white', 8: 'black', 9: 'deep_blue', 10: 'orange', 11: 'purple', 12: 'pale_green', 13: 'pale_turquoise', 14: 'grey', 15: 'white'}¶
- __init__(value: int | str = 0) None[source]¶
Initialize color attribute.
- Parameters:
value – Color value (0-255) or color name string
- Raises:
ValueError – If value is invalid
- get_color_name() str | None[source]¶
Get the color name for base colors.
- Returns:
Color name if it’s a base color (0-15), None otherwise
- is_base_color() bool[source]¶
Check if this is a base 16 color.
- Returns:
True if color is in base 16 range (0-15)
- is_extended_color() bool[source]¶
Check if this is an extended color.
- Returns:
True if color is in extended range (16-255)
- class pure3270.emulation.field_attributes.HighlightAttribute(value: int | str = 0)[source]¶
Bases:
ExtendedAttributeHighlight attribute for visual highlighting effects.
Supports various highlighting effects like blink, reverse video, underscore, and intensity levels.
- NORMAL = 0¶
- BLINK = 1¶
- REVERSE = 2¶
- UNDERSCORE = 4¶
- INTENSITY_HIGH = 8¶
- INTENSITY_LOW = 16¶
- EFFECT_NAMES = {0: 'normal', 1: 'blink', 2: 'reverse', 4: 'underscore', 8: 'high_intensity', 16: 'low_intensity'}¶
- __init__(value: int | str = 0) None[source]¶
Initialize highlight attribute.
- Parameters:
value – Highlight value or effect name
- Raises:
ValueError – If value is invalid
- get_effect_name() str | None[source]¶
Get the effect name for known effects.
- Returns:
Effect name if recognized, None otherwise
- has_effect(effect: int) bool[source]¶
Check if a specific effect is enabled.
- Parameters:
effect – Effect constant to check
- Returns:
True if effect is enabled
- set_effect(effect: int, enabled: bool = True) None[source]¶
Set or clear a specific effect.
- Parameters:
effect – Effect constant
enabled – Whether to enable or disable the effect
- class pure3270.emulation.field_attributes.ValidationAttribute(value: int | str = 0, min_length: int | None = None, max_length: int | None = None, custom_rule: str | None = None)[source]¶
Bases:
ExtendedAttributeValidation attribute for field validation rules.
Supports various validation constraints like mandatory fields, numeric-only input, length limits, and custom validation rules.
- NONE = 0¶
- MANDATORY = 1¶
- NUMERIC = 2¶
- ALPHABETIC = 4¶
- ALPHANUMERIC = 8¶
- LENGTH_MIN = 16¶
- LENGTH_MAX = 32¶
- CUSTOM = 64¶
- VALIDATION_NAMES = {0: 'none', 1: 'mandatory', 2: 'numeric', 4: 'alphabetic', 8: 'alphanumeric', 16: 'min_length', 32: 'max_length', 64: 'custom'}¶
- __init__(value: int | str = 0, min_length: int | None = None, max_length: int | None = None, custom_rule: str | None = None) None[source]¶
Initialize validation attribute.
- Parameters:
value – Validation type value or name
min_length – Minimum field length (if LENGTH_MIN set)
max_length – Maximum field length (if LENGTH_MAX set)
custom_rule – Custom validation rule string (if CUSTOM set)
- Raises:
ValueError – If parameters are invalid
- get_validation_name() str | None[source]¶
Get the validation type name.
- Returns:
Validation type name if recognized, None otherwise
- has_validation(validation_type: int) bool[source]¶
Check if a specific validation type is enabled.
- Parameters:
validation_type – Validation type constant
- Returns:
True if validation type is enabled
- set_validation(validation_type: int, enabled: bool = True) None[source]¶
Set or clear a specific validation type.
- Parameters:
validation_type – Validation type constant
enabled – Whether to enable or disable the validation
- validate_input(input_text: str) Tuple[bool, str | None][source]¶
Validate input text against validation rules.
- Parameters:
input_text – The input text to validate
- Returns:
Tuple of (is_valid, error_message)
- class pure3270.emulation.field_attributes.OutliningAttribute(value: int | str = 0)[source]¶
Bases:
ExtendedAttributeOutlining attribute for field borders and outlines.
Supports various outlining styles like boxes, underlines, overlines, and custom border patterns.
- NONE = 0¶
- UNDERLINE = 1¶
- OVERLINE = 2¶
- LEFT_LINE = 4¶
- RIGHT_LINE = 8¶
- BOX = 15¶
- DOUBLE_LINE = 16¶
- DASHED = 32¶
- DOTTED = 64¶
- STYLE_NAMES = {0: 'none', 1: 'underline', 2: 'overline', 4: 'left_line', 8: 'right_line', 15: 'box', 16: 'double_line', 32: 'dashed', 64: 'dotted'}¶
- __init__(value: int | str = 0) None[source]¶
Initialize outlining attribute.
- Parameters:
value – Outlining style value or name
- Raises:
ValueError – If value is invalid
- get_style_name() str | None[source]¶
Get the outlining style name.
- Returns:
Style name if recognized, None otherwise
- has_style(style: int) bool[source]¶
Check if a specific outlining style is enabled.
- Parameters:
style – Style constant to check
- Returns:
True if style is enabled
- set_style(style: int, enabled: bool = True) None[source]¶
Set or clear a specific outlining style.
- Parameters:
style – Style constant
enabled – Whether to enable or disable the style
- is_box() bool[source]¶
Check if this is a complete box outline.
- Returns:
True if all four sides are outlined
- class pure3270.emulation.field_attributes.LightPenAttribute(value: int | str = 0)[source]¶
Bases:
ExtendedAttributeLight pen attribute for designating a field as light-pen selectable.
- class pure3270.emulation.field_attributes.BackgroundAttribute(value: int | str = 0)[source]¶
Bases:
ExtendedAttributeBackground color attribute supporting base 16 and extended 256 color support.
Supports both standard 3270 background colors (0-15) and extended colors (16-255) as defined in TN3270E specifications.
- BASE_COLORS = {0: 'neutral_black', 1: 'blue', 2: 'red', 3: 'pink', 4: 'green', 5: 'turquoise', 6: 'yellow', 7: 'neutral_white', 8: 'black', 9: 'deep_blue', 10: 'orange', 11: 'purple', 12: 'pale_green', 13: 'pale_turquoise', 14: 'grey', 15: 'white'}¶
- __init__(value: int | str = 0) None[source]¶
Initialize background color attribute.
- Parameters:
value – Background color value (0-255) or color name string
- Raises:
ValueError – If value is invalid
- get_color_name() str | None[source]¶
Get the background color name for base colors.
- Returns:
Color name if it’s a base color (0-15), None otherwise
- is_base_color() bool[source]¶
Check if this is a base 16 background color.
- Returns:
True if color is in base 16 range (0-15)
- is_extended_color() bool[source]¶
Check if this is an extended background color.
- Returns:
True if color is in extended range (16-255)
- class pure3270.emulation.field_attributes.CharacterSetAttribute(value: int | str = 0)[source]¶
Bases:
ExtendedAttributeCharacter set attribute for field-specific character set selection.
Supports various character sets as defined in 3270 and TN3270E specifications including APL, Katakana, and user-defined character sets.
- CHARACTER_SETS = {0: 'default', 1: 'apl', 2: 'katakana', 3: 'user1', 4: 'user2', 5: 'user3', 6: 'user4', 65: 'dbcs_katakana', 66: 'dbcs_hiragana', 67: 'dbcs_kanji', 68: 'dbcs_mixed', 69: 'dbcs_chinese', 70: 'dbcs_korean', 241: 'dbcs_chinese_host', 242: 'dbcs_japanese_host', 243: 'dbcs_korean_host', 244: 'dbcs_thai_host', 245: 'dbcs_arabic_host', 246: 'dbcs_hebrew_host', 247: 'dbcs_latin2_host', 248: 'dbcs_latin3_host', 249: 'dbcs_latin4_host', 250: 'dbcs_greek_host', 251: 'dbcs_cyrillic_host', 252: 'dbcs_turkish_host', 253: 'dbcs_latin5_host', 254: 'dbcs_japanese_extended'}¶
Extended Position¶
Extended position class with 14-bit addressing support for large screen emulation.
- class pure3270.emulation.extended_position.ExtendedPosition(row: int = 0, col: int = 0, cols: int = 80, addressing_mode: AddressingMode = AddressingMode.MODE_12_BIT)[source]¶
Bases:
objectRepresents a position in a 3270 screen buffer with support for extended 14-bit addressing.
This class provides coordinate-based positioning with automatic conversion to/from linear addresses, supporting both traditional 12-bit and extended 14-bit addressing modes.
- __init__(row: int = 0, col: int = 0, cols: int = 80, addressing_mode: AddressingMode = AddressingMode.MODE_12_BIT) None[source]¶
Initialize an ExtendedPosition.
- Parameters:
row – Row coordinate (0-based)
col – Column coordinate (0-based)
cols – Number of columns in the screen (default 80)
addressing_mode – Addressing mode for validation and conversion
- Raises:
ValueError – If coordinates are invalid for the addressing mode
- property addressing_mode: AddressingMode¶
Get the addressing mode.
- set_coordinates(row: int, col: int) None[source]¶
Set new coordinates for this position.
- Parameters:
row – New row coordinate
col – New column coordinate
- Raises:
ValueError – If new coordinates are invalid
- set_from_address(address: int) None[source]¶
Set coordinates from a linear address.
- Parameters:
address – Linear address to convert from
- Raises:
ValueError – If address is invalid for the addressing mode
- convert_addressing_mode(new_mode: AddressingMode) ExtendedPosition[source]¶
Create a new ExtendedPosition with the same coordinates but different addressing mode.
- Parameters:
new_mode – New addressing mode
- Returns:
New ExtendedPosition instance with converted addressing mode
- Raises:
ValueError – If coordinates are invalid in the new mode
- is_valid_for_mode(mode: AddressingMode) bool[source]¶
Check if this position is valid for a given addressing mode.
- Parameters:
mode – Addressing mode to check against
- Returns:
True if position is valid for the mode, False otherwise
Extended Screen Buffer¶
Extended screen buffer with 14-bit addressing support for large screen emulation.
- class pure3270.emulation.extended_screen_buffer.ExtendedScreenBuffer(rows: int = 24, cols: int = 80, init_value: int = 64, addressing_mode: AddressingMode = AddressingMode.MODE_12_BIT)[source]¶
Bases:
ScreenBufferExtended screen buffer supporting 14-bit addressing for large screens.
This class extends the traditional ScreenBuffer to support larger screen sizes through 14-bit addressing while maintaining full backward compatibility with existing ScreenBuffer API.
- __init__(rows: int = 24, cols: int = 80, init_value: int = 64, addressing_mode: AddressingMode = AddressingMode.MODE_12_BIT)[source]¶
Initialize the ExtendedScreenBuffer.
- Parameters:
rows – Number of rows (default 24)
cols – Number of columns (default 80)
init_value – Initial value for buffer positions (default 0x40 for EBCDIC space)
addressing_mode – Addressing mode for the buffer
- Raises:
ValueError – If dimensions exceed addressing mode limits
- property addressing_mode: AddressingMode¶
Get the addressing mode for this buffer.
- property extended_cursor: ExtendedPosition¶
Get the extended cursor position.
- set_position(row: int, col: int, wrap: bool = False, strict: bool = False) None[source]¶
Set cursor position with extended addressing validation.
- Parameters:
row – Row coordinate
col – Column coordinate
wrap – Whether to wrap coordinates to valid range
strict – If True, raise IndexError on out of bounds; if False, clamp values
- Raises:
ValueError – If position is invalid for the addressing mode
IndexError – When strict=True and position is out of bounds
- set_position_from_address(address: int) None[source]¶
Set cursor position from a linear address.
- Parameters:
address – Linear address to set cursor to
- Raises:
ValueError – If address is invalid for the addressing mode
- get_position_address() int[source]¶
Get the current cursor position as a linear address.
- Returns:
Linear address of current cursor position
- write_char_at_address(ebcdic_byte: int, address: int, protected: bool = False, circumvent_protection: bool = False) None[source]¶
Write a character at a specific linear address.
- Parameters:
ebcdic_byte – EBCDIC byte value to write
address – Linear address to write to
protected – Whether to set protection attribute
circumvent_protection – Whether to write even to protected fields
- Raises:
ValueError – If address is invalid for the addressing mode
- read_char_at_address(address: int) int | None[source]¶
Read a character from a specific linear address.
- Parameters:
address – Linear address to read from
- Returns:
EBCDIC byte value at the address, or None if address is invalid
- is_address_valid(address: int) bool[source]¶
Check if an address is valid for this buffer’s addressing mode.
- Parameters:
address – Address to validate
- Returns:
True if address is valid, False otherwise
- get_address_range() Tuple[int, int][source]¶
Get the valid address range for this buffer.
- Returns:
Tuple of (min_address, max_address) inclusive
- convert_addressing_mode(new_mode: AddressingMode) ExtendedScreenBuffer | None[source]¶
Create a new ExtendedScreenBuffer with the same content but different addressing mode.
- Parameters:
new_mode – New addressing mode
- Returns:
New ExtendedScreenBuffer instance, or None if conversion fails
- Raises:
ValueError – If current buffer size exceeds new mode limits
- get_field_at_address(address: int) Field | None[source]¶
Get the field containing a specific linear address.
- Parameters:
address – Linear address to check
- Returns:
Field containing the address, or None if no field or invalid address
- move_cursor_to_address(address: int) None[source]¶
Move cursor to a specific linear address.
- Parameters:
address – Linear address to move cursor to
- Raises:
ValueError – If address is invalid
Addressing¶
Addressing mode enumeration and utilities for 3270 emulation.
- class pure3270.emulation.addressing.AddressingMode(value)[source]¶
Bases:
EnumEnumeration of supported 3270 addressing modes.
- MODE_12_BIT = '12-bit'¶
Traditional 12-bit addressing mode supporting up to 4096 positions (24x80, 32x80, etc.).
- MODE_14_BIT = '14-bit'¶
Extended 14-bit addressing mode supporting up to 16384 positions for large screens.
- class pure3270.emulation.addressing.AddressCalculator[source]¶
Bases:
objectUtility class for address calculations and conversions between addressing modes.
- static validate_address(address: int, mode: AddressingMode) bool[source]¶
Validate if an address is valid for the given addressing mode.
- Parameters:
address – The address to validate (0-based linear position)
mode – The addressing mode to validate against
- Returns:
True if address is valid for the mode, False otherwise
- static address_to_coords(address: int, cols: int, mode: AddressingMode) Tuple[int, int] | None[source]¶
Convert a linear address to row/column coordinates.
- Parameters:
address – Linear address (0-based)
cols – Number of columns in the screen
mode – Addressing mode
- Returns:
Tuple of (row, col) coordinates, or None if address is invalid
- static coords_to_address(row: int, col: int, cols: int, mode: AddressingMode) int | None[source]¶
Convert row/column coordinates to a linear address.
- Parameters:
row – Row coordinate (0-based)
col – Column coordinate (0-based)
cols – Number of columns in the screen
mode – Addressing mode
- Returns:
Linear address, or None if coordinates would exceed mode limits
- static get_max_positions(mode: AddressingMode) int[source]¶
Get the maximum number of positions supported by the addressing mode.
- Parameters:
mode – The addressing mode
- Returns:
Maximum number of positions (1-based, so max address + 1)
- static convert_address_mode(address: int, from_mode: AddressingMode, to_mode: AddressingMode, cols: int) int | None[source]¶
Convert an address from one addressing mode to another.
This is primarily useful for converting between 12-bit and 14-bit addressing when the same row/column coordinates are used but different linear addressing.
- Parameters:
address – The address to convert
from_mode – Source addressing mode
to_mode – Target addressing mode
cols – Number of columns (needed for coordinate conversion)
- Returns:
Converted address, or None if conversion is not possible
Buffer Writer¶
Common base class for buffer writers in pure3270 emulation.
- class pure3270.emulation.buffer_writer.BufferWriter[source]¶
Bases:
ABCAbstract base class consolidating write operations, cursor management, and content retrieval for screen, printer, and session buffers.
- abstract write_char(ebcdic_byte: int, row: int | None = None, col: int | None = None, protected: bool = False, circumvent_protection: bool = False) None[source]¶
Write an EBCDIC character to the buffer at specified or current position. Handles insertion, protection checks, and overflow where applicable.
Snapshot¶
Screen buffer snapshot and comparison system for regression testing.
- class pure3270.emulation.snapshot.ScreenSnapshot(screen_buffer: ScreenBuffer)[source]¶
Bases:
objectRepresents a snapshot of a ScreenBuffer state for regression testing.
- __init__(screen_buffer: ScreenBuffer)[source]¶
Create a snapshot from a ScreenBuffer instance.
- classmethod from_dict(data: Dict[str, Any]) ScreenSnapshot[source]¶
Create snapshot from dictionary data.
- classmethod from_json(json_str: str) ScreenSnapshot[source]¶
Create snapshot from JSON string.
- to_screen_buffer() ScreenBuffer[source]¶
Reconstruct a ScreenBuffer from this snapshot.
- classmethod load_from_file(filepath: str) ScreenSnapshot[source]¶
Load snapshot from a JSON file.
- class pure3270.emulation.snapshot.SnapshotComparison(snapshot1: ScreenSnapshot, snapshot2: ScreenSnapshot)[source]¶
Bases:
objectRepresents the result of comparing two snapshots.
- __init__(snapshot1: ScreenSnapshot, snapshot2: ScreenSnapshot)[source]¶
Compare two snapshots and identify differences.
- pure3270.emulation.snapshot.take_snapshot(screen_buffer: ScreenBuffer) ScreenSnapshot[source]¶
Convenience function to take a snapshot of a ScreenBuffer.
- pure3270.emulation.snapshot.create_ascii_mode_snapshot(screen_buffer: ScreenBuffer) ScreenSnapshot[source]¶
Create a snapshot with the screen buffer in ASCII mode.
- pure3270.emulation.snapshot.create_ebcdic_mode_snapshot(screen_buffer: ScreenBuffer) ScreenSnapshot[source]¶
Create a snapshot with the screen buffer in EBCDIC mode.
- pure3270.emulation.snapshot.compare_snapshots(snapshot1: ScreenSnapshot, snapshot2: ScreenSnapshot) SnapshotComparison[source]¶
Convenience function to compare two snapshots.
- class pure3270.emulation.snapshot.SnapshotDiffer(snapshot1: ScreenSnapshot, snapshot2: ScreenSnapshot)[source]¶
Bases:
objectAdvanced snapshot comparison with detailed diff analysis.
- __init__(snapshot1: ScreenSnapshot, snapshot2: ScreenSnapshot)[source]¶
Initialize differ with two snapshots.
- get_buffer_diff_positions() List[Tuple[int, int, int, int]][source]¶
Get positions where buffer bytes differ.
Regression Harness¶
Exceptions¶
Enhanced exceptions for pure3270 with contextual information.
- exception pure3270.exceptions.Pure3270Error(message: str, context: Dict[str, Any] | None = None, original_exception: Exception | None = None)[source]¶
Bases:
ExceptionBase error for pure3270 with contextual information.
- __init__(message: str, context: Dict[str, Any] | None = None, original_exception: Exception | None = None)[source]¶
Initialize a pure3270 error.
- Parameters:
message – Error message
context – Optional context information (host, port, operation, stream_pos, order_byte, trace, etc.)
original_exception – Original exception that caused this error
- exception pure3270.exceptions.ConnectionError(message: str, context: Dict[str, Any] | None = None, original_exception: Exception | None = None)[source]¶
Bases:
Pure3270ErrorConnection error with connection-specific context.
- exception pure3270.exceptions.NegotiationError(message: str, context: Dict[str, Any] | None = None, original_exception: Exception | None = None)[source]¶
Bases:
Pure3270ErrorNegotiation error with protocol-specific context.
- exception pure3270.exceptions.ParseError(message: str, context: Dict[str, Any] | None = None, original_exception: Exception | None = None)[source]¶
Bases:
Pure3270ErrorParsing error with data-specific context.
- exception pure3270.exceptions.ProtocolError(message: str, context: Dict[str, Any] | None = None, original_exception: Exception | None = None)[source]¶
Bases:
Pure3270ErrorProtocol error with protocol-specific context.
- exception pure3270.exceptions.TimeoutError(message: str, context: Dict[str, Any] | None = None, original_exception: Exception | None = None)[source]¶
Bases:
Pure3270ErrorTimeout error with operation-specific context.