mirror of
https://gitee.com/infiniflow/ragflow.git
synced 2025-12-06 07:19:03 +08:00
Move singleton to common directory (#10935)
### What problem does this PR solve? As title ### Type of change - [x] Refactoring Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
@@ -36,18 +36,7 @@ from api.utils.json_encode import json_dumps, json_loads
|
||||
from api.utils.configs import deserialize_b64, serialize_b64
|
||||
|
||||
from common.time_utils import current_timestamp, timestamp_to_date, date_string_to_timestamp
|
||||
|
||||
|
||||
def singleton(cls, *args, **kw):
|
||||
instances = {}
|
||||
|
||||
def _singleton():
|
||||
key = str(cls) + str(os.getpid())
|
||||
if key not in instances:
|
||||
instances[key] = cls(*args, **kw)
|
||||
return instances[key]
|
||||
|
||||
return _singleton
|
||||
from common.decorator import singleton
|
||||
|
||||
|
||||
CONTINUOUS_FIELD_TYPE = {IntegerField, FloatField, DateTimeField}
|
||||
|
||||
27
common/decorator.py
Normal file
27
common/decorator.py
Normal file
@@ -0,0 +1,27 @@
|
||||
#
|
||||
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import os
|
||||
|
||||
def singleton(cls, *args, **kw):
|
||||
instances = {}
|
||||
|
||||
def _singleton():
|
||||
key = str(cls) + str(os.getpid())
|
||||
if key not in instances:
|
||||
instances[key] = cls(*args, **kw)
|
||||
return instances[key]
|
||||
|
||||
return _singleton
|
||||
@@ -15,23 +15,10 @@
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
import tiktoken
|
||||
|
||||
from api.utils.file_utils import get_project_base_directory
|
||||
|
||||
|
||||
def singleton(cls, *args, **kw):
|
||||
instances = {}
|
||||
|
||||
def _singleton():
|
||||
key = str(cls) + str(os.getpid())
|
||||
if key not in instances:
|
||||
instances[key] = cls(*args, **kw)
|
||||
return instances[key]
|
||||
|
||||
return _singleton
|
||||
|
||||
tiktoken_cache_dir = get_project_base_directory()
|
||||
os.environ["TIKTOKEN_CACHE_DIR"] = tiktoken_cache_dir
|
||||
# encoder = tiktoken.encoding_for_model("gpt-3.5-turbo")
|
||||
|
||||
@@ -19,7 +19,7 @@ import os
|
||||
import time
|
||||
from io import BytesIO
|
||||
from rag import settings
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
from azure.storage.blob import ContainerClient
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import logging
|
||||
import os
|
||||
import time
|
||||
from rag import settings
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
from azure.identity import ClientSecretCredential, AzureAuthorityHosts
|
||||
from azure.storage.filedatalake import FileSystemClient
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ from elasticsearch_dsl import UpdateByQuery, Q, Search, Index
|
||||
from elastic_transport import ConnectionTimeout
|
||||
from rag import settings
|
||||
from rag.settings import TAG_FLD, PAGERANK_FLD
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
from api.utils.file_utils import get_project_base_directory
|
||||
from api.utils.common import convert_bytes
|
||||
from rag.utils.doc_store_conn import DocStoreConnection, MatchExpr, OrderByExpr, MatchTextExpr, MatchDenseExpr, \
|
||||
|
||||
@@ -27,7 +27,7 @@ from infinity.connection_pool import ConnectionPool
|
||||
from infinity.errors import ErrorCode
|
||||
from rag import settings
|
||||
from rag.settings import PAGERANK_FLD, TAG_FLD
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
import pandas as pd
|
||||
from api.utils.file_utils import get_project_base_directory
|
||||
from rag.nlp import is_english
|
||||
|
||||
@@ -21,7 +21,7 @@ from minio.commonconfig import CopySource
|
||||
from minio.error import S3Error
|
||||
from io import BytesIO
|
||||
from rag import settings
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
|
||||
|
||||
@singleton
|
||||
|
||||
@@ -4,7 +4,7 @@ import pymysql
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
from api.utils.configs import get_base_config
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
|
||||
|
||||
CREATE_TABLE_SQL = """
|
||||
|
||||
@@ -26,7 +26,7 @@ from opensearchpy import UpdateByQuery, Q, Search, Index
|
||||
from opensearchpy import ConnectionTimeout
|
||||
from rag import settings
|
||||
from rag.settings import TAG_FLD, PAGERANK_FLD
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
from api.utils.file_utils import get_project_base_directory
|
||||
from rag.utils.doc_store_conn import DocStoreConnection, MatchExpr, OrderByExpr, MatchTextExpr, MatchDenseExpr, \
|
||||
FusionExpr
|
||||
|
||||
@@ -19,7 +19,7 @@ from botocore.exceptions import ClientError
|
||||
from botocore.config import Config
|
||||
import time
|
||||
from io import BytesIO
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
from rag import settings
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import uuid
|
||||
|
||||
import valkey as redis
|
||||
from rag import settings
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
from valkey.lock import Lock
|
||||
import trio
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from botocore.exceptions import ClientError
|
||||
from botocore.config import Config
|
||||
import time
|
||||
from io import BytesIO
|
||||
from rag.utils import singleton
|
||||
from common.decorator import singleton
|
||||
from rag import settings
|
||||
|
||||
@singleton
|
||||
|
||||
79
test/unit_test/common/test_decorator.py
Normal file
79
test/unit_test/common/test_decorator.py
Normal file
@@ -0,0 +1,79 @@
|
||||
#
|
||||
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from common.decorator import singleton
|
||||
|
||||
|
||||
# Test class for demonstration
|
||||
@singleton
|
||||
class TestClass:
|
||||
def __init__(self):
|
||||
self.counter = 0
|
||||
|
||||
def increment(self):
|
||||
self.counter += 1
|
||||
return self.counter
|
||||
|
||||
|
||||
# Test cases
|
||||
class TestSingleton:
|
||||
|
||||
def test_state_persistence(self):
|
||||
"""Test that instance state persists across multiple calls"""
|
||||
instance1 = TestClass()
|
||||
instance1.increment()
|
||||
instance1.increment()
|
||||
|
||||
instance2 = TestClass()
|
||||
assert instance2.counter == 2 # State should persist
|
||||
|
||||
def test_multiple_calls_consistency(self):
|
||||
"""Test consistency across multiple calls"""
|
||||
instances = [TestClass() for _ in range(5)]
|
||||
|
||||
# All references should point to the same object
|
||||
first_instance = instances[0]
|
||||
for instance in instances:
|
||||
assert instance is first_instance
|
||||
|
||||
def test_instance_methods_work(self):
|
||||
"""Test that instance methods work correctly"""
|
||||
instance = TestClass()
|
||||
|
||||
# Test method calls
|
||||
result1 = instance.increment()
|
||||
result2 = instance.increment()
|
||||
|
||||
assert result1 == 3
|
||||
assert result2 == 4
|
||||
assert instance.counter == 4
|
||||
|
||||
|
||||
# Test decorator itself
|
||||
def test_singleton_decorator_returns_callable():
|
||||
"""Test that the decorator returns a callable"""
|
||||
|
||||
class PlainClass:
|
||||
pass
|
||||
|
||||
decorated_class = singleton(PlainClass)
|
||||
|
||||
# Should return a function
|
||||
assert callable(decorated_class)
|
||||
|
||||
# Calling should return an instance of PlainClass
|
||||
instance = decorated_class()
|
||||
assert isinstance(instance, PlainClass)
|
||||
Reference in New Issue
Block a user