Skip to content

Commit 7e04f57

Browse files
authored
Merge pull request #11 from dxFeed/EN-1414-refactor-sub-dealloc
En 1414 refactor sub dealloc
2 parents 63186a9 + 0e269a0 commit 7e04f57

File tree

3 files changed

+27
-34
lines changed

3 files changed

+27
-34
lines changed

dxfeed/core/DXFeedPy.pyx

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# distutils: language = c++
22
# cython: always_allow_keywords=True
3-
from libcpp.deque cimport deque as cppdq
43

54
from dxfeed.core.utils.helpers cimport *
65
from dxfeed.core.utils.helpers import *
@@ -12,6 +11,7 @@ from datetime import datetime
1211
import pandas as pd
1312
from typing import Optional, Union, Iterable
1413
from warnings import warn
14+
from weakref import WeakSet
1515

1616
# for importing variables
1717
import dxfeed.core.listeners.listener as lis
@@ -53,24 +53,29 @@ cdef class ConnectionClass:
5353
Data structure that contains connection
5454
"""
5555
cdef clib.dxf_connection_t connection
56-
# sub_ptr_list contains pointers to all subscriptions related to current connection
57-
cdef cppdq[clib.dxf_subscription_t *] sub_ptr_list
58-
# each subscription has its own index in a list
59-
cdef int subs_order
56+
cdef object __sub_refs
6057

6158
def __init__(self):
62-
self.subs_order = 0
59+
self.__sub_refs = WeakSet()
6360

6461
def __dealloc__(self):
6562
dxf_close_connection(self)
6663

64+
def get_sub_refs(self):
65+
"""
66+
Method to get list of references to all subscriptions related to current connection
67+
68+
Returns
69+
-------
70+
:list
71+
List of weakref objects. Empty list if no refs
72+
"""
73+
return list(self.__sub_refs)
74+
6775
cpdef SubscriptionClass make_new_subscription(self, data_len: int):
6876
cdef SubscriptionClass out = SubscriptionClass(data_len)
6977
out.connection = self.connection
70-
self.sub_ptr_list.push_back(&out.subscription) # append pointer to new subscription
71-
out.subscription_order = self.subs_order # assign each subscription an index
72-
self.subs_order += 1
73-
out.con_sub_list_ptr = &self.sub_ptr_list # reverse pointer to pointers list
78+
self.__sub_refs.add(out)
7479
return out
7580

7681

@@ -80,9 +85,8 @@ cdef class SubscriptionClass:
8085
"""
8186
cdef clib.dxf_connection_t connection
8287
cdef clib.dxf_subscription_t subscription
83-
cdef int subscription_order # index in list of subscription pointers
84-
cdef cppdq[clib.dxf_subscription_t *] *con_sub_list_ptr # pointer to list of subscription pointers
8588
cdef dxf_event_listener_t listener
89+
cdef object __weakref__ # Weak referencing enabling
8690
cdef object event_type_str
8791
cdef list columns
8892
cdef object data
@@ -105,9 +109,7 @@ cdef class SubscriptionClass:
105109
self.listener = NULL
106110

107111
def __dealloc__(self):
108-
if self.subscription: # if connection is not closed
109-
clib.dxf_close_subscription(self.subscription)
110-
self.con_sub_list_ptr[0][self.subscription_order] = NULL
112+
dxf_close_subscription(self)
111113

112114
def get_data(self):
113115
"""
@@ -187,7 +189,7 @@ def dxf_create_connection_auth_bearer(address: Union[str, unicode, bytes],
187189
address = address.encode('utf-8')
188190
token = token.encode('utf-8')
189191
clib.dxf_create_connection_auth_bearer(address, token,
190-
NULL, NULL, NULL, NULL, NULL, &cc.connection)
192+
NULL, NULL, NULL, NULL, NULL, &cc.connection)
191193
error_code = process_last_error(verbose=False)
192194
if error_code:
193195
raise RuntimeError(f"In underlying C-API library error {error_code} occurred!")
@@ -229,7 +231,7 @@ def dxf_create_subscription(ConnectionClass cc, event_type: str, candle_time: Op
229231
candle_time = datetime.strptime(candle_time, '%Y-%m-%d %H:%M:%S') if candle_time else datetime.utcnow()
230232
timestamp = int((candle_time - datetime(1970, 1, 1)).total_seconds()) * 1000 - 5000
231233
except ValueError:
232-
raise Exception("Inapropriate date format, should be %Y-%m-%d %H:%M:%S")
234+
raise Exception("Inappropriate date format, should be %Y-%m-%d %H:%M:%S")
233235

234236
if event_type == 'Candle':
235237
clib.dxf_create_subscription_timed(sc.connection, et_type_int, timestamp, &sc.subscription)
@@ -368,16 +370,11 @@ def dxf_close_connection(ConnectionClass cc):
368370
cc: ConnectionClass
369371
Variable with connection information
370372
"""
371-
372-
# close all subscriptions before closing the connection
373-
for i in range(cc.sub_ptr_list.size()):
374-
if cc.sub_ptr_list[i]: # subscription should not be closed previously
375-
clib.dxf_close_subscription(cc.sub_ptr_list[i][0])
376-
cc.sub_ptr_list[i][0] = NULL # mark subscription as closed
377-
378-
cc.sub_ptr_list.clear()
379-
380373
if cc.connection:
374+
related_subs = cc.get_sub_refs()
375+
for sub in related_subs:
376+
dxf_close_subscription(sub)
377+
381378
clib.dxf_close_connection(cc.connection)
382379
cc.connection = NULL
383380

@@ -393,7 +390,6 @@ def dxf_close_subscription(SubscriptionClass sc):
393390
if sc.subscription:
394391
clib.dxf_close_subscription(sc.subscription)
395392
sc.subscription = NULL
396-
sc.con_sub_list_ptr[0][sc.subscription_order] = NULL
397393

398394
def dxf_get_current_connection_status(ConnectionClass cc, return_str: bool=True):
399395
"""

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "dxfeed"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
description = "DXFeed Python API via C API"
55
authors = ["Index Management Team <[email protected]>"]
66
build = "build.py"

tests/test_dxfeedpy.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import dxfeed as dx
22
import pytest
33

4+
45
class ValueStorage(object): # config
56
demo_address = 'demo.dxfeed.com:7300'
67
event_types = ['Trade', 'Quote', 'Summary', 'Profile', 'Order', 'TimeAndSale', 'Candle', 'TradeETH', 'SpreadOrder',
@@ -39,8 +40,7 @@ def test_fail_create_subscription_with_no_connection():
3940

4041

4142
@pytest.mark.xfail()
42-
def test_fail_to_use_subscription_without_connection():
43-
connection = dx.dxf_create_connection(ValueStorage.demo_address)
43+
def test_fail_to_use_subscription_without_connection(connection):
4444
sub = dx.dxf_create_subscription(cc=connection, event_type='Trade')
4545
dx.dxf_close_connection(connection)
4646
dx.dxf_add_symbols(sc=sub, symbols=['AAPL'])
@@ -99,9 +99,7 @@ def test_symbol_clearing(connection):
9999

100100

101101
@pytest.mark.parametrize('sub_type', ValueStorage.event_types)
102-
def test_default_listeners(sub_type):
103-
# fixture usage causes errors with, probably, threads
104-
connection = dx.dxf_create_connection(ValueStorage.demo_address)
102+
def test_default_listeners(connection, sub_type):
105103
con_err_status = dx.process_last_error(verbose=False)
106104
sub = dx.dxf_create_subscription(connection, sub_type)
107105
sub_err_status = dx.process_last_error(verbose=False)
@@ -110,6 +108,5 @@ def test_default_listeners(sub_type):
110108
dx.dxf_detach_listener(sub)
111109
drop_lis_err_status = dx.process_last_error(verbose=False)
112110
dx.dxf_close_subscription(sub)
113-
dx.dxf_close_connection(connection)
114111
assert (con_err_status, sub_err_status, add_lis_err_status, drop_lis_err_status) == (0, 0, 0, 0)
115112

0 commit comments

Comments
 (0)