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:
Jin Hai
2025-11-02 12:24:08 +08:00
committed by GitHub
parent fe4852cb71
commit 6447b737ab
14 changed files with 117 additions and 35 deletions

View File

@@ -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
View 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

View File

@@ -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")

View File

@@ -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

View File

@@ -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

View File

@@ -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, \

View File

@@ -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

View File

@@ -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

View File

@@ -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 = """

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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)