Skip to content

SPOT : SymbolFilters does not deserialize correctly, instance is always None #476

@mobias17

Description

@mobias17

Description

The SymbolFilters oneOf model fails to populate the actual_instance field during deserialization in all versions >= 2.1.0 and loses all the information. This makes it impossible to access individual filter data (PriceFilter, LotSizeFilter, etc.) through the model's standard interface.

While ExchangeFilters was not the cleanest model however workable with in versions <= 2.0.0 SymbolFilters is not usable anymore.

Impact

Applications cannot access exchange filter data (filter type/instance, tick size, step size, min/max values, etc.)

Steps to Reproduce

import os
import logging

from binance_sdk_spot.spot import Spot, ConfigurationRestAPI, SPOT_REST_API_PROD_URL

# Configure logging
logging.basicConfig(level=logging.INFO)

# Create configuration for the REST API
configuration_rest_api = ConfigurationRestAPI(
    api_key=os.getenv("API_KEY", ""),
    api_secret=os.getenv("API_SECRET", ""),
    base_path=os.getenv("BASE_PATH", SPOT_REST_API_PROD_URL),
)

# Initialize Spot client
client = Spot(config_rest_api=configuration_rest_api)


def exchange_info():
    try:
        response = client.rest_api.exchange_info()

        rate_limits = response.rate_limits
        logging.info(f"exchange_info() rate limits: {rate_limits}")

        data = response.data()
        logging.info(f"exchange_info() response: {data}")

        # Try to access filter data
        symbol_filter = exchange_info.symbols[0].filters[0]

        print(f"actual_instance: {symbol_filter.actual_instance}")
        # Expected: <PriceFilter object>
        # Actual: None
        
        # All validator fields are also None
        print(f"oneof_schema_1_validator: {symbol_filter.oneof_schema_1_validator}")
        # Expected: <PriceFilter object> or None (if not matching)
        # Actual: None (always)

    except Exception as e:
        logging.error(f"exchange_info() error: {e}")


if __name__ == "__main__":
    exchange_info()

Expected Behavior

The SymbolFilters.actual_instance field should contain the parsed filter object (e.g., PriceFilter, LotSizeFilter, etc.) based on the filterType field in the JSON.

Example to possible expected outcome:

# For a PRICE_FILTER in the JSON
{
    "filterType": "PRICE_FILTER",
    "minPrice": "0.00001000",
    "maxPrice": "922327.00000000",
    "tickSize": "0.00001000"
}

# Should result in or something similar to:
filter_obj.actual_instance  # <PriceFilter instance>
filter_obj.actual_instance.tick_size  # "0.00001000"

Actual Behavior

filter_obj.actual_instance  # None
filter_obj.to_dict()  # None
filter_obj.model_dump()  # All validators are None

# Output:
{
    'oneof_schema_1_validator': None,
    'oneof_schema_2_validator': None,
    # ... all 16 validators are None
    'actual_instance': None
}

Possible Root Cause

The SymbolFilters.from_dict() method attempts to deserialize into each possible filter type but fails to populate actual_instance when a match is found. The method increments match counter but doesn't store the successfully parsed instance.

Environment

  • SDK Version: 2.1.0 through 6.0.0
  • Python Version: 3.12.0
  • OS: Windows 11 (but affects all platforms)
  • binance-common Version: Tested with 2.0.0 and 3.3.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions