config

#ifndef _STOCK_CONFIG_H_
#define _STOCK_CONFIG_H_
 
 
typedef unsigned long		ulong;
typedef unsigned int		uint;
typedef unsigned short		ushort;
typedef unsigned char		uchar;
 
 
#endif
 

#ifndef _TDX_STOCK_H_
#define _TDX_STOCK_H_
#include "stdafx.h"
#include <fstream>
#include <set>
#include <vector>
#include <map>
 
 
#include "config.h"
 
 
using namespace std;
 
#define STOCK_CODE_LEN  6
 
enum PacketType
{
	PKT_TYPE_RESPONSE=0x00,
	PKT_TYPE_REQUEST=0x01,
	PKT_TYPE_QUOTES=0x02
};
 
enum MarketType
{
	MKT_TYPE_SHENZHEN=0x00,
	MKT_TYPE_SHANGHAI=0x01
};
 
enum PostFix
{
	POSTFIX_GET_STOCK_COUNT = 0x0133c775
};
 
 
enum CmdId
{
	CMD_STOCKHOLD_CHANGE = 0x000f,
	CMD_STOCK_LIST = 0x0524,
	CMD_HEART_BEAT = 0x0523,
	CMD_GET_STOCK_COUNT= 0x044e,
	CMD_GET_STOCK_QUOTES = 0x053e,
	CMD_GET_MINUTE_DATA = 0x051d,
	CMD_GET_HIS_MINUTE_DATA = 0x0fb4,
	CMD_GET_TRANSACTION_DATA = 0x0fc5,
	CMD_GET_HIS_TRANSACTION_DATA = 0x0fb5,
	CMD_GET_INDEX_BARS = 0x052d
};
 
typedef set<stringStringSet;
struct MarketInfo
{
	enum MarketType
	{
		MARKET_FIRST,
		MARKET_SHANGHAI_A = MARKET_FIRST,
		MARKET_SHANGHAI_B,
		MARKET_SHENZHEN_A,
		MARKET_SHENZHEN_B,
		MARKET_WARRANT,		// 权证
		MARKET_INDEX ,			// 指数
		MARKET_MAX,
		MARKET_UNKNOWN = MARKET_MAX,
	};
	static char get_block_from_market_type(MarketType t)
	{
		switch(t)
		{
		case MARKET_SHANGHAI_A:
			return 0;
		case MARKET_SHANGHAI_B:
			return 1;
		case MARKET_SHENZHEN_A:
			return 2;
		case MARKET_SHENZHEN_B:
			return 3;
		case MARKET_INDEX:
			return 11;			// 所有指数
		case MARKET_WARRANT:
			return 13;			// 权证
		default:
			throw 0;
		}
	}
	static unsigned int stocks_count[MARKET_MAX];
	static StringSet stocks_set[MARKET_MAX];
 
	const static int StocksCodeLen = 6;	// 100  股一手
	const static int StocksPerHand = 100;	// 100  股一手.
	const static float tax;				// 0.3 %
 
	static short get_market_type_from_code( const char* pCode )
	{
		if ( pCode[0] == '0' )
		{
			if ( pCode[1] == '0' )
				return MARKET_SHENZHEN_A;
			else
				return MARKET_WARRANT;		// 03xxxx
		}
		else if ( pCode[0] == '2' )
			return MARKET_SHENZHEN_B;
		else if ( pCode[0] == '3' )				// 3xxxxx
			return MARKET_INDEX;
		else if ( pCode[0] == '6' )
			return MARKET_SHANGHAI_A;
		else if ( pCode[0] == '9' )
		{
			if ( pCode[1] == '0' )
				return MARKET_SHANGHAI_B;	// 90xxxx
			else
				return MARKET_INDEX;		// 99xxxx
		}
		else if ( pCode[0] == '5' )
			return MARKET_WARRANT;
		else
			return MARKET_UNKNOWN;
	}
 
	static short get_market_type(const char* pCode)
	{
		return get_market_type_from_code(pCode);
	}
 
	static short get_market_type( const string& stock_code )
	{
		const char* pCode = stock_code.c_str();
		return get_market_type_from_code( pCode );
	}
 
	static char get_market_location_from_code( const char* pCode )
	{
		if ( pCode[0] <= '4' )
			return 0;					// 深圳 00xxxx, 03xxxx, 02xxxx, 3xxxxx(深圳指数)
		else
			return 1;					//上海 60xxxxx, 58xxxx, 99xxxx (上海指数)
	}
 
	static char get_market_location(const char* pCode)
	{
		return get_market_location_from_code(pCode);
	}
 
	static char get_market_location(const string& stock_code)
	{
		const char* pCode = stock_code.c_str();
		return get_market_location_from_code(pCode);
	}
 
	static string get_first_stock();
	static string find_next_stock(const string& stock_code);
 
};
 
class StockTransact
{
public:
	struct Transact
	{
		short		minute;
		int			price;
		int 			vol;
		int 			count;	// 此笔成交量的成交次数。 0: 表示未知
		uchar		bs;		// 表示买成交量还是卖成交量0:buy, 1:sell
		bool operator == (const Transact& t);
		template<class Archive>
		void serialize(Archive & ar, const unsigned int version)
		{
			ar & minute;
			ar & price;
			ar & vol;
			ar & bs;
		}
	};
	typedef vector<TransactDailyTransact;
	typedef map<stringDailyTransactDateTransact;
	typedef map<uintDateTransactTransactMap;
};
 
extern StockTransact::DateTransact		today_transact;
extern StockTransact::TransactMap		hist_transact;
 
class StockBid
{
public:
	struct Bid			// 盘口
	{
		int			minute;
		int			act;				// 活跃度 active rate
 
		int			price;			// 现价
		int			y_close;			// 昨收
		int			open;			// 开盘
		int			high;			// 最高
		int			low;				// 最低
		int			buy;			// 买入
		int			sell;			// 卖出
 
		int			total_vol;		// 总手,以股数计算
		int			avail_vol;		// 现手,以股数计算
		int			inner_vol;		// 内盘
		int			outer_vol;		// 外盘
 
		int			updown;			// 单笔升跌
 
		int			buy_price1;	// 买价1
		int			sell_price1;
		int			buy_vol1;	// 买量1
		int			sell_vol1;
		int			buy_price2;
		int			sell_price2;
		int			buy_vol2;
		int			sell_vol2;
		int			buy_price3;
		int			sell_price3;
		int			buy_vol3;
		int			sell_vol3;
		int			buy_price4;
		int			sell_price4;
		int			buy_vol4;
		int			sell_vol4;
		int			buy_price5;
		int			sell_price5;
		int			buy_vol5;
		int			sell_vol5;
 
		char  stock_code[7];
		int  update_time;
		template<class Archive>
		void serialize(Archive & ar, const unsigned int version)
		{
			ar & minute;
			ar & act;
 
			ar & price;
			ar & y_close;
			ar & open;
			ar & high;
			ar & low;
			ar & buy;
			ar & sell;
 
			ar & total_vol;
			ar & avail_vol;
			ar & inner_vol;
			ar & outer_vol;
 
			ar & updown;
 
			ar &	buy_price1;	// 买价1
			ar &	sell_price1;
			ar &	buy_vol1;	// 买量1
			ar &	sell_vol1;
			ar &	buy_price2;
			ar &	sell_price2;
			ar &	buy_vol2;
			ar &	sell_vol2;
			ar &	buy_price3;
			ar &	sell_price3;
			ar &	buy_vol3;
			ar &	sell_vol3;
			ar &	buy_price4;
			ar &	sell_price4;
			ar &	buy_vol4;
			ar &	sell_vol4;
			ar &	buy_price5;
			ar &	sell_price5;
			ar &	buy_vol5;
			ar &	sell_vol5;
		}
	};
	typedef vector<BidDailyBid;
	typedef map<uintDailyBidDateBid;
	typedef map<stringDateBidBidMap;
};
extern StockBid::BidMap instant_price_list;
 
typedef vector<stringStringVector;
 
struct BaseInfo
{
	string			stock_code;
	uint				update_time;	
	double			ttl_amount;			// 总股本
	double			state_own_amount;	// 国家股
	double			init_amount;			// 发起股本
	double			corp_amount;		// 法人股本
	double			b_amount;			// B 股本
	double			h_amount;			// H 股本
	double			cir_amount;			// 流通 股本
	double			empl_amount;		// 职工 股本
	double			unknown1;			// 
	double			ttl_asset;			// 总资产
	double			varible_asset;		// 流动 资产
	double			firm_asset;			// 固定 资产
	double			invisible_asset;		// 无形 资产
	double			long_term_invest;	// 长期投资
	double			varible_debt;		// 流动负债
	double			long_term_debt;		// 长期负债
	double			accu_fund;			// 公积金
	double			net_asset;			// 净资产
	double			major_income;		// 主营收入
	double			major_profit;		// 主营利润
	double			unknown2;			// 
	double			bussiness_income;	// 营业收入
	double			invest_income;		// 营业收入
	double			allowance;			// 补贴收入
	double			non_bussiness_income;	// 业外收入
	double			income_adjustment;	// 收入调整
	double			ttl_profit;			// 利润总额
	double			unknown3;			// 
	double			net_profit;			// 税后利润
	double			undist_profit;		// 未分配利润
	double			per_net_assert2;	// 每股净资产2
	static const int		record_len;
};
 
 
typedef map<stringBaseInfoStockBaseInfoMap;
typedef map<stringStringVectorStockGroupMap;
 
extern fstreamoperator >> (fstream& ifs, BaseInfo& bs);
 
typedef map<stringStringVectorStringVectorMap;
 
 
 
struct GBBQ
{
	string			code;
	uchar			chg_type;
	// 变更类型 
	// 1: 正常 
	// 2: 与1相关的除权除息日股本变化 
	// 3:股本性质变化(例如职工股上市)
	// 6: 增发. 
	// 8: 增发上市
 
	union {
		struct {
			float				cash;	 			// 每10 分红
			float				sell_price;			// 每股配售价格
			float				give_count;			// 每10 股送股数
			float				sell_count;			// 每10 股配售数
		}bonus;
		struct 
		{
			float				old_cir;	 			// 旧流通股
			float				old_ttl;				// 旧总股本
			float				new_cir;			// 新流通股
			float				new_ttl;				// 新总股本
		}gb;
	}data;
	template<class Archive>
	void serialize(Archive & ar, const unsigned int version)
	{
		ar & dt;
		ar & chg_type;
		ar & data.bonus.cash;
		ar & data.bonus.sell_price;
		ar & data.bonus.give_count;
		ar & data.bonus.sell_count;
	}
};
 
typedef vector<GBBQDateGBBQ;
typedef map<uintDateGBBQGBBQMap;
 
class StockBasicInfo
{
public:
	bool load_basic_info();
	void save_basic_info();
	bool load_block_info();
	void save_block_info();
	void clear_gbbq_info();
	//	bool load_gbbq_info(gregorian::date start_date, int day_count);
	void save_gbbq_info(uint tr_date);
	void save_stock_set();
	void add_stock_gbbq(uint dt, const GBBQ& gbbq);
	string get_gbbq_file_name(uint tr_date);
	bool is_gbbq_file_exist(uint tr_date);
private:
	StockBaseInfoMap 		stock_base_info;
	StockGroupMap		stock_block_info;
	GBBQMap			stock_gbbq_info;
};
 
 
struct QuotePara
{
	uchar cMarket;
	char sStockCode[6];
};
 
struct MinuteData
{
	int iPriceRaw;
	int iReserved1;
	int iVol;
};
 
struct MatchedData
{
	int iHour;
	int iMinute;
	int iPriceRaw;
	int iVol;
	int iNum;
	int iBuyOrSell;
	int iReserved;
};
 
struct IndexBarsData
{
	int iYear;
	int iMonth;
	int iDay;
	int iHour;
	int iMinute;
	int iPriceOpenDiff;
	int iPriceCloseDiff;
	int iPriceHighDiff;
	int iPriceLowDiff;
	int iVolRaw;
	int iDbVolRaw;
	int iUpCount;
	int iDownCount;
};
 
///////////////////////////////////////////////////////////////////////////////
//
//  Semantic actions
//
///////////////////////////////////////////////////////////////////////////////
extern 	void show_curr_bid(char const*  first, char const*  last );
 
struct ReqTimeInfo
{
	uint m_iSeqId;
	string m_sBeginTime;
	string m_sEndTime;
	LARGE_INTEGER  nBeginTime;
	LARGE_INTEGER  nEndTime;
 
	//GetIndexBarsReq专用
	int iCategory;
};
 
 
 
#endif
 



// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
 
#pragma once
 
//#include "targetver.h"
 
#include <stdio.h>
#include <tchar.h>
 
#include <winsock2.h>
#include <windows.h>
 
 
 
// TODO: 在此处引用程序需要的其他头文件


#ifndef _UTIL_HPP_
#define _UTIL_HPP_
#include "stdafx.h"
 
#include <string>
 
extern void log_packet(const char* data, size_t len);
extern void test_packet_from_file(const std::string& filename );
extern 	const uchar * stock_code_search (const uchar * str, unsigned int len);
extern bool stockcode_is_valid(const uchar * s);
extern bool is_file_exist(const std::string& filename);
 
std::string get_raw_string(std::string const& s);
int getNowStr( std::string& sNow  );
 
double getTimeDiffconst LARGE_INTEGER&  a,  const LARGE_INTEGER&  b );
 
//=====================================
 
int SetNonBlockSOCKET  iSock, unsigned long on );
int SetNoDelaySOCKET  iSock,  char on );
int SetLingerSOCKET iSock, struct linger stLinger );
#endif


#include "stdafx.h"
#include "config.h"

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>


#include "response.h"
#include "stock.h"
#include <Windows.h>


using namespace std;

bool is_file_exist(const string& filename)
{
	bool isOpen;
	ifstream ifs;
	ifs.open(filename.c_str());
	isOpen = ifs.is_open();
	ifs.close();
	return isOpen;
}

bool stockcode_is_valid(const uchar * s)
{
	bool valid = true;
	for(int i = 0; i < MarketInfo::StocksCodeLen; ++i)
	{
		if(s[i] < '0' || s[i] > '9')
		{
			valid = false;
			break;
		}
	}
	return valid;
}

const uchar * stock_code_search (const uchar * str, unsigned int len)
{
	const uchar *cp = str;
	while (len -- > 0)
	{
		if(stockcode_is_valid(cp))
			return cp;
		cp++;
	}
	return 0;
}

void log_packet(const char* data, size_t len)
{
	const string path = "F:\\Develop\\stock\\data\\exc_log\\exc";
	string filename;

	for(int i = 0; i < 1000; i++)
	{
		stringstream ss;
		ss << i << ".dat";
		filename = path + ss.str();
		if(!is_file_exist(filename))
		{
			ofstream ofs(filename.c_str(),  ios::out | ios::binary);
			ofs.write(data, len);
			break;
		}
	}
}


std::string get_raw_string(std::string const& s)
{
	std::ostringstream out;
	out << '\"';
	out << std::hex;
	for (std::string::const_iterator it = s.begin(); it != s.end(); ++it)
	{
		// AND 0xFF will remove the leading "ff" in the output,
		// So that we could get "\xab" instead of "\xffab"
		out << " " << (static_cast<short>(*it) & 0xff);
	}
	out << '\"';
 
	ofstream outfile;
    outfile.open( "D:\\1.txt" );
 
	outfile<<out.str() << endl;
	outfile.close();
 
	return out.str();
}

int getNowStr( std::string& sNow )
{
	SYSTEMTIME stNow;   
	GetLocalTime( &stNow );
	char sNowStr[32];
	memset( sNowStr, 0, sizeof( sNowStr ) );
	sprintf( sNowStr, "%4d-%02d-%02d %02d:%02d:%02d.%03d",stNow.wYear,stNow.wMonth,stNow.wDay,
		stNow.wHour,stNow.wMinute, stNow.wSecond,stNow.wMilliseconds  );
	sNow = sNowStr;
	return 0;
}
 
double  getTimeDiffconst LARGE_INTEGER&   nBeginTime,  
	const LARGE_INTEGER& nEndTime )
{
	 LARGE_INTEGER  nFreq;
 
     QueryPerformanceFrequency( &nFreq ); // 获取时钟周期
	 //cout << "nFreq.QuadPart is:" << nFreq.QuadPart << endl;
 
    return  (double)(nEndTime.QuadPart- nBeginTime.QuadPart)*1000.0/ nFreq.QuadPart;
}
 
//=============================
 
 
int SetNonBlockSOCKET  iSock, unsigned long on )
{
	return ioctlsocket( iSock, FIONBIO, &on );
}
 
int SetNoDelaySOCKET  iSock,  char on )
{
     return setsockopt(   iSock,   IPPROTO_TCP,   TCP_NODELAY,   &on,   sizeof(char));   
}
 
int SetLingerSOCKET  iSock,  struct linger stLinger )
{
	return setsockopt( iSock, SOL_SOCKETSO_LINGER, 
		(char FAR *) &stLinger, sizeof(stLinger) );
}


#include "stdafx.h"
#include "config.h"
 
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <sstream>
#include "stockio.h"
 
#include "util.hpp"
 
#include "stock.h"
 
using namespace std;
 
 
 
//	using namespace assign;
 
const float MarketInfo::tax = 0.01f;				// 1 %
 
unsigned int MarketInfo::stocks_count[MarketInfo::MARKET_MAX];
StringSet	 MarketInfo::stocks_set[MarketInfo::MARKET_MAX];
 
 
StockTransact::DateTransact		today_transact;
StockTransact::TransactMap		hist_transact;
StockBid::BidMap 				instant_price_list;
 
 
string StockBasicInfo::get_gbbq_file_name(uint tr_date)
{
	const string stock_gbbq_file = "F:\\Develop\\stock\\data\\G";
	stringstream ss;
	ss << stock_gbbq_file << tr_date << ".mat";
	return ss.str();
}
 
bool StockBasicInfo::is_gbbq_file_exist(uint tr_date)
{
	return is_file_exist(get_gbbq_file_name(tr_date));
}
 
void StockBasicInfo::clear_gbbq_info()
{
	stock_gbbq_info.clear();
}
 
 
 
 
bool StockBasicInfo::load_basic_info()
{
	// 加载股票基本资料
	// 基本信息
	stock_base_info.clear();
 
	BaseInfo	bs;
	const string stock_data_path = "C:\\Program Files\\xyzq\\T0002\\";
	string full_path = stock_data_path + "BASE.DBF";
	fstream fs(full_path.c_str(), ios::in);
//	fstream ofs("d:\\temp\\t.txt", ios::out);
 
	if(!fs)	return false;
 
	int record_off = 0x522;
	fs.seekg(record_off);
	char c;
	fs >> c;
	while(!fs.eof() && -1 != fs.tellg())
	{
		fs >> bs;
		record_off += BaseInfo::record_len;
		stock_base_info.insert(make_pair(bs.stock_code, bs));
//		ofs << bs.stock_code << endl;
		fs.seekg(record_off);
		fs >> c;
	}
	return true;
 
}
 
 
 
bool StockBasicInfo::load_block_info()
{
	// 加载板块资料
	stock_block_info.clear();
 
	const string stock_data_path = "C:\\Program Files\\xyzq\\T0002\\";
	string full_path = stock_data_path + "BLOCK.DAT";
	fstream fs(full_path.c_str(), ios::in | ios::binary);
	if(!fs)	return false;
 
	int p = 0;
	fs.seekg(0x182);
	while(!fs.eof() && -1 != (p =fs.tellg()))
	{
		char temp[10];
		fs.read(&temp[0],9);
		if(0 == temp[0]) break;
		string name(temp);		// block name
 
		unsigned short cnt = 0;
		fs.read((char*)&cnt, 2);
		fs.seekg(2, ios::cur);
		while(cnt -- > 0)
		{
			fs.read(&temp[0],7);
			if(0 == temp[0]) break;
			string member(temp, 6);
 
			stock_block_info[name].push_back(member);
		}
		fs.seekg(p + 0x0afd);
	}
	return true;
}
 
 
 
 
 
void StockBasicInfo::add_stock_gbbq(uint dt, const GBBQ& gbbq)
{
	stock_gbbq_info[dt].push_back(gbbq);
}
 
bool StockTransact::Transact::operator == (const StockTransact::Transact& t)
{
	return (minute == t.minute
		&& price == t.price
		&& vol == t.vol
		&& bs == t.bs);
}
 
const int BaseInfo::record_len = 0x1e1;
fstreamoperator >> (fstream& fs, BaseInfo& bs)
{
	char code[MarketInfo::StocksCodeLen];
 
	fs.read(code, MarketInfo::StocksCodeLen);
	bs.stock_code = string(&code[0], MarketInfo::StocksCodeLen);
 
	fs >> bs.update_time;
	fs >> bs.ttl_amount;
	fs >> bs.state_own_amount;	// 国家股
	fs >> bs.init_amount;		// 发起股本
	fs >> bs.corp_amount;		// 法人股本
	fs >> bs.b_amount;			// B 股本
	fs >> bs.h_amount;			// H 股本
	fs >> bs.cir_amount;		// 流通 股本
	fs >> bs.empl_amount;		// 职工 股本
	fs >> bs.unknown1;			// 
	fs >> bs.ttl_asset;			// 总资产
	fs >> bs.varible_asset;		// 流动 资产
	fs >> bs.firm_asset;		// 固定 资产
	fs >> bs.invisible_asset;	// 无形 资产
	fs >> bs.long_term_invest;	// 长期投资
	fs >> bs.varible_debt;		// 流动负债
	fs >> bs.long_term_debt;	// 长期负债
	fs >> bs.accu_fund;			// 公积金
	fs >> bs.net_asset;			// 净资产
	fs >> bs.major_income;		// 主营收入
	fs >> bs.major_profit;		// 主营利润
	fs >> bs.unknown2;			// 
	fs >> bs.bussiness_income;	// 营业收入
	fs >> bs.invest_income;		// 投资收入
	fs >> bs.allowance;			// 补贴收入
	fs >> bs.non_bussiness_income;	// 业外收入
	fs >> bs.income_adjustment;	// 收入调整
	fs >> bs.ttl_profit;		// 利润总额
	fs >> bs.unknown3;			// 
	fs >> bs.net_profit;		// 税后利润
	fs >> bs.undist_profit;		// 未分配利润
	fs >> bs.per_net_assert2;	// 每股净资产2
	return fs;
	
}
 
extern void output_short_index_data();
 
 
 
string MarketInfo::get_first_stock()
{
	// set the first stock
	for(short m = MarketInfo::MARKET_FIRST; m < MarketInfo::MARKET_MAX; m++)
	{
		StringSet::const_iterator iter = MarketInfo::stocks_set[m].begin();
		if(iter != MarketInfo::stocks_set[m].end())
		{
			return *iter;
		}
	}
	return "";
}
 
string MarketInfo::find_next_stock(const string& stock_code)
{
	bool first_in_market = false;
	for(short m = MarketInfo::get_market_type(stock_code); m < MarketInfo::MARKET_MAX; m++)
	{
		StringSet::const_iterator iter ;
		if(! first_in_market)
		{
			iter = MarketInfo::stocks_set[m].find(stock_code);
			if( iter != MarketInfo::stocks_set[m].end())
			{
				++iter;
				if(iter != MarketInfo::stocks_set[m].end())
				{
					return *iter;
				}
			}
			first_in_market = true;
		}
		else
		{
			iter = MarketInfo::stocks_set[m].begin();
			if(iter != MarketInfo::stocks_set[m].end())
			{
				return *iter;
			}
		}
	}
	return "";
}
 
 
void show_curr_bid(char const*  first, char const*  last )
{
	cout << "show_curr_bid called\r\n";
 
	StockBid::BidMap::const_iterator i = instant_price_list.begin();
 
	// has data
	if(i != instant_price_list.end())
	{
		// print title here
	}
	while(i++ != instant_price_list.end())
	{
		cout << i->first << endl;
	}
 
}
	




                
# E:\AI_System\core\config.py import os import yaml from pathlib import Path from typing import Any, Dict, Optional, Union import logging from .exceptions import ConfigError class ConfigManager: """配置管理系统,支持环境变量、配置文件和默认值""" def __init__(self, base_dir: str, env_prefix: str = "AI_SYSTEM_"): """ 初始化配置管理器 Args: base_dir: 基础目录路径 env_prefix: 环境变量前缀 """ self.base_dir = Path(base_dir) self.env_prefix = env_prefix self.config = {} self.logger = logging.getLogger("ConfigManager") # 创建必要目录 self._create_necessary_dirs() # 加载配置 self._load_config() def _create_necessary_dirs(self): """创建系统必需的目录结构""" required_dirs = [ self.base_dir / "data", self.base_dir / "logs", self.base_dir / "config", self.base_dir / "models", self.base_dir / "cache" ] for dir_path in required_dirs: dir_path.mkdir(parents=True, exist_ok=True) self.logger.info(f"确保目录存在: {dir_path}") def _load_config(self): """加载配置 - 优先级:环境变量 > 配置文件 > 默认值""" # 1. 加载默认配置 self.config = self._get_default_config() # 2. 加载配置文件 config_path = self.base_dir / "config" / "system_config.yaml" if config_path.exists(): try: with open(config_path, 'r', encoding='utf-8') as f: file_config = yaml.safe_load(f) or {} self._merge_config(file_config) self.logger.info(f"从文件加载配置: {config_path}") except Exception as e: self.logger.error(f"配置文件解析错误: {str(e)}") raise ConfigError(f"配置文件解析错误: {str(e)}") else: self.logger.warning(f"配置文件不存在: {config_path}") # 3. 加载环境变量 self._load_env_vars() # 4. 验证必需配置项 self._validate_required_config() def _get_default_config(self) -> Dict[str, Any]: """获取默认配置""" return { # 系统核心配置 "SYSTEM_NAME": "AI_System", "LOG_LEVEL": "INFO", "LOG_DIR": str(self.base_dir / "logs"), # 线程和进程配置 "MAX_WORKERS": max(1, os.cpu_count() * 2), # 默认CPU核心数*2 "MAX_THREADS_PER_WORKER": 10, # 网络配置 "API_HOST": "0.0.0.0", "API_PORT": 5000, "API_TIMEOUT": 30, # 资源限制 "MEMORY_LIMIT_MB": 4096, "CPU_LIMIT_PERCENT": 80, # 智能体配置 "AGENT_TYPE": "autonomous", "AGENT_UPDATE_INTERVAL": 60, # 秒 "AGENT_MAX_TASKS": 100, # 数据库配置 "DB_PATH": str(self.base_dir / "data" / "system.db"), "DB_BACKUP_INTERVAL": 3600, # 秒 # 调试配置 "DEBUG_MODE": False, "PROFILE_PERFORMANCE": False } def _merge_config(self, new_config: Dict[str, Any]): """合并配置(递归更新字典)""" def merge_dict(base: Dict, update: Dict): for key, value in update.items(): if isinstance(value, dict) and key in base and isinstance(base[key], dict): merge_dict(base[key], value) else: base[key] = value merge_dict(self.config, new_config) def _load_env_vars(self): """从环境变量加载配置""" for key, value in self.config.items(): env_key = f"{self.env_prefix}{key}" env_value = os.environ.get(env_key) if env_value is not None: # 尝试转换类型 if isinstance(value, bool): self.config[key] = env_value.lower() in ('true', '1', 'yes') elif isinstance(value, int): try: self.config[key] = int(env_value) except ValueError: self.logger.warning(f"环境变量 {env_key} 无法转换为整数: {env_value}") elif isinstance(value, float): try: self.config[key] = float(env_value) except ValueError: self.logger.warning(f"环境变量 {env_key} 无法转换为浮点数: {env_value}") else: self.config[key] = env_value self.logger.info(f"从环境变量加载: {key}={self.config[key]}") def _validate_required_config(self): """验证必需配置项是否存在""" required_keys = [ "MAX_WORKERS", "API_HOST", "API_PORT", "DB_PATH", "LOG_DIR", "LOG_LEVEL" ] missing_keys = [key for key in required_keys if key not in self.config] if missing_keys: error_msg = f"缺少必需配置项: {', '.join(missing_keys)}" self.logger.error(error_msg) raise ConfigError(error_msg) def get(self, key: str, default: Optional[Any] = None) -> Any: """获取配置值""" return self.config.get(key, default) def __getattr__(self, key: str) -> Any: """通过属性访问配置""" if key in self.config: return self.config[key] raise AttributeError(f"配置项 '{key}' 不存在") def __getitem__(self, key: str) -> Any: """通过索引访问配置""" if key in self.config: return self.config[key] raise KeyError(f"配置项 '{key}' 不存在") def __contains__(self, key: str) -> bool: """检查配置项是否存在""" return key in self.config def save_config(self, file_path: Optional[Union[str, Path]] = None): """保存当前配置到文件""" if file_path is None: file_path = self.base_dir / "config" / "system_config.yaml" file_path = Path(file_path) file_path.parent.mkdir(parents=True, exist_ok=True) try: with open(file_path, 'w', encoding='utf-8') as f: yaml.safe_dump(self.config, f, sort_keys=False, allow_unicode=True) self.logger.info(f"配置已保存到: {file_path}") return True except Exception as e: self.logger.error(f"保存配置失败: {str(e)}") return False def reload(self): """重新加载配置""" self.logger.info("重新加载配置...") self._load_config() self.logger.info("配置重新加载完成") def print_config(self, show_all: bool = False): """打印当前配置(安全地隐藏敏感信息)""" sensitive_keys = ["API_KEY", "DB_PASSWORD", "SECRET_KEY"] print("\n当前系统配置:") for key, value in self.config.items(): if key in sensitive_keys and not show_all: print(f"{key}: {'*' * 8}") else: print(f"{key}: {value}") print() # 全局配置实例 _system_config = None def get_config(base_dir: Optional[str] = None, env_prefix: str = "AI_SYSTEM_") -> ConfigManager: """获取全局配置实例(单例模式)""" global _system_config if _system_config is None: if base_dir is None: # 尝试从环境变量获取基础目录 base_dir = os.environ.get(f"{env_prefix}BASE_DIR", os.getcwd()) _system_config = ConfigManager(base_dir=base_dir, env_prefix=env_prefix) return _system_config # 示例使用 if __name__ == "__main__": # 初始化配置 config = get_config(base_dir=os.getcwd()) # 访问配置 print("API端口:", config.API_PORT) print("最大工作线程数:", config.MAX_WORKERS) # 打印配置 config.print_config() # 保存配置 config.save_config() # 测试代码 def test_config_system(): # 设置测试环境变量 os.environ["AI_SYSTEM_API_PORT"] = "8080" os.environ["AI_SYSTEM_DEBUG_MODE"] = "true" # 创建临时目录 import tempfile with tempfile.TemporaryDirectory() as tmpdir: # 创建配置文件 config_path = Path(tmpdir) / "config" / "system_config.yaml" config_path.parent.mkdir(parents=True, exist_ok=True) with open(config_path, 'w') as f: f.write("MAX_WORKERS: 16\nLOG_LEVEL: DEBUG") # 初始化配置 config = ConfigManager(base_dir=tmpdir, env_prefix="AI_SYSTEM_") # 验证配置 assert config.API_PORT == 8080 # 来自环境变量 assert config.MAX_WORKERS == 16 # 来自配置文件 assert config.DEBUG_MODE is True # 环境变量转换 assert config.LOG_LEVEL == "DEBUG" # 来自配置文件 # 测试默认值 assert config.MEMORY_LIMIT_MB == 4096 # 默认值 print("所有测试通过!") if __name__ == "__main__": test_config_system() # E:\AI_System\core\config.py import os import yaml from pathlib import Path from typing import Any, Dict, Optional, Union import logging from .exceptions import ConfigError class ConfigManager: """配置管理系统,支持环境变量、配置文件和默认值""" def __init__(self, base_dir: str, env_prefix: str = "AI_SYSTEM_"): """ 初始化配置管理器 Args: base_dir: 基础目录路径 env_prefix: 环境变量前缀 """ self.base_dir = Path(base_dir) self.env_prefix = env_prefix self.config = {} self.logger = logging.getLogger("ConfigManager") # 创建必要目录 self._create_necessary_dirs() # 加载配置 self._load_config() def _create_necessary_dirs(self): """创建系统必需的目录结构""" required_dirs = [ self.base_dir / "data", self.base_dir / "logs", self.base_dir / "config", self.base_dir / "models", self.base_dir / "cache" ] for dir_path in required_dirs: dir_path.mkdir(parents=True, exist_ok=True) self.logger.info(f"确保目录存在: {dir_path}") def _load_config(self): """加载配置 - 优先级:环境变量 > 配置文件 > 默认值""" # 1. 加载默认配置 self.config = self._get_default_config() # 2. 加载配置文件 config_path = self.base_dir / "config" / "system_config.yaml" if config_path.exists(): try: with open(config_path, 'r', encoding='utf-8') as f: file_config = yaml.safe_load(f) or {} self._merge_config(file_config) self.logger.info(f"从文件加载配置: {config_path}") except Exception as e: self.logger.error(f"配置文件解析错误: {str(e)}") raise ConfigError(f"配置文件解析错误: {str(e)}") else: self.logger.warning(f"配置文件不存在: {config_path}") # 3. 加载环境变量 self._load_env_vars() # 4. 验证必需配置项 self._validate_required_config() def _get_default_config(self) -> Dict[str, Any]: """获取默认配置""" return { # 系统核心配置 "SYSTEM_NAME": "AI_System", "LOG_LEVEL": "INFO", "LOG_DIR": str(self.base_dir / "logs"), # 线程和进程配置 "MAX_WORKERS": max(1, os.cpu_count() * 2), # 默认CPU核心数*2 "MAX_THREADS_PER_WORKER": 10, # 网络配置 "API_HOST": "0.0.0.0", "API_PORT": 5000, "API_TIMEOUT": 30, # 资源限制 "MEMORY_LIMIT_MB": 4096, "CPU_LIMIT_PERCENT": 80, # 智能体配置 "AGENT_TYPE": "autonomous", "AGENT_UPDATE_INTERVAL": 60, # 秒 "AGENT_MAX_TASKS": 100, # 数据库配置 "DB_PATH": str(self.base_dir / "data" / "system.db"), "DB_BACKUP_INTERVAL": 3600, # 秒 # 调试配置 "DEBUG_MODE": False, "PROFILE_PERFORMANCE": False } def _merge_config(self, new_config: Dict[str, Any]): """合并配置(递归更新字典)""" def merge_dict(base: Dict, update: Dict): for key, value in update.items(): if isinstance(value, dict) and key in base and isinstance(base[key], dict): merge_dict(base[key], value) else: base[key] = value merge_dict(self.config, new_config) def _load_env_vars(self): """从环境变量加载配置""" for key, value in self.config.items(): env_key = f"{self.env_prefix}{key}" env_value = os.environ.get(env_key) if env_value is not None: # 尝试转换类型 if isinstance(value, bool): self.config[key] = env_value.lower() in ('true', '1', 'yes') elif isinstance(value, int): try: self.config[key] = int(env_value) except ValueError: self.logger.warning(f"环境变量 {env_key} 无法转换为整数: {env_value}") elif isinstance(value, float): try: self.config[key] = float(env_value) except ValueError: self.logger.warning(f"环境变量 {env_key} 无法转换为浮点数: {env_value}") else: self.config[key] = env_value self.logger.info(f"从环境变量加载: {key}={self.config[key]}") def _validate_required_config(self): """验证必需配置项是否存在""" required_keys = [ "MAX_WORKERS", "API_HOST", "API_PORT", "DB_PATH", "LOG_DIR", "LOG_LEVEL" ] missing_keys = [key for key in required_keys if key not in self.config] if missing_keys: error_msg = f"缺少必需配置项: {', '.join(missing_keys)}" self.logger.error(error_msg) raise ConfigError(error_msg) def get(self, key: str, default: Optional[Any] = None) -> Any: """获取配置值""" return self.config.get(key, default) def __getattr__(self, key: str) -> Any: """通过属性访问配置""" if key in self.config: return self.config[key] raise AttributeError(f"配置项 '{key}' 不存在") def __getitem__(self, key: str) -> Any: """通过索引访问配置""" if key in self.config: return self.config[key] raise KeyError(f"配置项 '{key}' 不存在") def __contains__(self, key: str) -> bool: """检查配置项是否存在""" return key in self.config def save_config(self, file_path: Optional[Union[str, Path]] = None): """保存当前配置到文件""" if file_path is None: file_path = self.base_dir / "config" / "system_config.yaml" file_path = Path(file_path) file_path.parent.mkdir(parents=True, exist_ok=True) try: with open(file_path, 'w', encoding='utf-8') as f: yaml.safe_dump(self.config, f, sort_keys=False, allow_unicode=True) self.logger.info(f"配置已保存到: {file_path}") return True except Exception as e: self.logger.error(f"保存配置失败: {str(e)}") return False def reload(self): """重新加载配置""" self.logger.info("重新加载配置...") self._load_config() self.logger.info("配置重新加载完成") def print_config(self, show_all: bool = False): """打印当前配置(安全地隐藏敏感信息)""" sensitive_keys = ["API_KEY", "DB_PASSWORD", "SECRET_KEY"] print("\n当前系统配置:") for key, value in self.config.items(): if key in sensitive_keys and not show_all: print(f"{key}: {'*' * 8}") else: print(f"{key}: {value}") print() # 全局配置实例 _system_config = None def get_config(base_dir: Optional[str] = None, env_prefix: str = "AI_SYSTEM_") -> ConfigManager: """获取全局配置实例(单例模式)""" global _system_config if _system_config is None: if base_dir is None: # 尝试从环境变量获取基础目录 base_dir = os.environ.get(f"{env_prefix}BASE_DIR", os.getcwd()) _system_config = ConfigManager(base_dir=base_dir, env_prefix=env_prefix) return _system_config # 示例使用 if __name__ == "__main__": # 初始化配置 config = get_config(base_dir=os.getcwd()) # 访问配置 print("API端口:", config.API_PORT) print("最大工作线程数:", config.MAX_WORKERS) # 打印配置 config.print_config() # 保存配置 config.save_config() # 测试代码 def test_config_system(): # 设置测试环境变量 os.environ["AI_SYSTEM_API_PORT"] = "8080" os.environ["AI_SYSTEM_DEBUG_MODE"] = "true" # 创建临时目录 import tempfile with tempfile.TemporaryDirectory() as tmpdir: # 创建配置文件 config_path = Path(tmpdir) / "config" / "system_config.yaml" config_path.parent.mkdir(parents=True, exist_ok=True) with open(config_path, 'w') as f: f.write("MAX_WORKERS: 16\nLOG_LEVEL: DEBUG") # 初始化配置 config = ConfigManager(base_dir=tmpdir, env_prefix="AI_SYSTEM_") # 验证配置 assert config.API_PORT == 8080 # 来自环境变量 assert config.MAX_WORKERS == 16 # 来自配置文件 assert config.DEBUG_MODE is True # 环境变量转换 assert config.LOG_LEVEL == "DEBUG" # 来自配置文件 # 测试默认值 assert config.MEMORY_LIMIT_MB == 4096 # 默认值 print("所有测试通过!") if __name__ == "__main__": test_config_system() Microsoft Windows [版本 10.0.22631.2861] (c) Microsoft Corporation。保留所有权利。 C:\Users\Administrator>cd /d E:\AI_System\web_ui E:\AI_System\web_ui>python server.py Traceback (most recent call last): File "E:\AI_System\web_ui\server.py", line 49, in <module> from core.config import CoreConfig as SystemConfig File "E:\AI_System\core\__init__.py", line 5, in <module> from .config import CoreConfig File "E:\AI_System\core\config.py", line 7, in <module> from .exceptions import ConfigError ImportError: cannot import name 'ConfigError' from 'core.exceptions' (E:\AI_System\core\exceptions.py) E:\AI_System\web_ui>
最新发布
08-13
<think>我们遇到了一个导入错误:ImportError: cannot import name 'ConfigError' from 'core.exceptions' (E:\AI_System\core\exceptions.py) 这意味着在core.exceptions模块中没有定义ConfigError异常类。 为了解决这个问题,我们需要: 1. 在core/exceptions.py文件中定义ConfigError类。 2. 确保在core/config.py中正确导入。 由于原代码中没有提供core/exceptions.py的内容,我们将创建这个文件并定义ConfigError。 步骤: 1. 在core目录下创建exceptions.py(如果不存在) 2. 在exceptions.py中定义ConfigError,它可以是Exception的子类。 3. 修改core/config.py,从core.exceptions导入ConfigError。 由于错误发生在运行server.py时,而server.py试图从core.config导入CoreConfig(但我们的类名为ConfigManager), 这提示我们可能需要调整导入方式。但是,根据错误信息,问题首先出在ConfigError的导入上,所以先解决这个。 我们先创建exceptions.py并定义ConfigError。 文件路径: E:\AI_System\core\exceptions.py 内容如下: ```python # core/exceptions.py class ConfigError(Exception): """配置相关的异常""" pass ``` 然后,确保core/config.py中的导入语句是: from .exceptions import ConfigError 另外,注意在server.py中导入的是: from core.config import CoreConfig as SystemConfig 但我们的配置管理类名为ConfigManager,所以需要调整server.py中的导入。 根据之前的代码,我们有一个函数get_config返回ConfigManager实例,并且我们使用单例模式。 在server.py中应该使用get_config函数来获取配置实例,而不是直接导入类。 因此,我们需要修改server.py中的导入: from core.config import get_config as get_system_config 然后使用: system_config = get_system_config() 但是,当前错误是ConfigError导入问题,我们先解决这个。 修改core/config.py的导入部分: from .exceptions import ConfigError 如果core/exceptions.py文件不存在,则创建。 由于错误提示是“cannot import name 'ConfigError'”,可能是exceptions.py中没有定义ConfigError,或者文件不存在。 因此,我们首先确保core/exceptions.py存在并且包含ConfigError类的定义。 如果core/exceptions.py已经存在,但没有ConfigError,则添加。 如果core/exceptions.py不存在,则创建并添加。 接下来,我们修改server.py的导入方式,因为原来的导入语句是`from core.config import CoreConfig as SystemConfig`, 而我们的配置类名为ConfigManager,所以这个导入会失败。因此,我们需要修改server.py,使用get_config函数。 但是,由于错误发生在导入core.config时,而core/config.py又导入了core.exceptions.ConfigError,所以首先确保这个导入成功。 我们将在core/exceptions.py中添加一些其他可能用到的异常,以便后续使用。 优化后的core/exceptions.py: ```python # E:\AI_System\core\exceptions.py class ConfigError(Exception): """配置相关的异常基类""" pass class InitializationError(Exception): """初始化异常""" pass class DependencyError(Exception): """依赖错误,如缺少必要模块""" pass class SubsystemFailure(Exception): """子系统故障""" pass ``` 然后,在core/config.py中,我们只导入需要的异常,即ConfigError。 现在,我们重新运行server.py,应该可以解决ConfigError导入问题。 但是,接下来可能会遇到server.py中导入CoreConfig失败的问题,因此我们提前修改server.py。 修改server.py中的导入部分: 原代码: from core.config import CoreConfig as SystemConfig 改为: from core.config import get_config system_config = get_config() 然后,在server.py中使用system_config代替原来的SystemConfig。 由于原代码中使用了SystemConfig,我们需要替换所有SystemConfig为system_config(注意,system_config是实例,不是类)。 例如,原代码可能这样使用: SystemConfig.get('KEY') 现在改为: system_config.get('KEY') 或者直接通过属性访问:system_config.KEY 由于ConfigManager实现了__getattr__,所以可以直接访问属性。 但是,请注意,在server.py中,我们可能是在模块级别导入的,所以需要先初始化配置。 我们可以这样修改server.py: # 在文件开始处 from core.config import get_config system_config = get_config(base_dir="E:/AI_System") # 根据实际情况指定base_dir 注意:base_dir应该根据实际情况设置,或者由环境变量提供。 由于我们之前配置管理器在初始化时需要base_dir,在get_config函数中,如果base_dir为None,则尝试从环境变量获取,否则使用当前工作目录。 因此,我们需要确保在调用get_config时传递正确的base_dir,或者设置环境变量AI_SYSTEM_BASE_DIR。 在server.py中,我们可以将base_dir设置为项目根目录(E:\AI_System)。 这样修改后,server.py应该可以正常运行。 总结步骤: 1. 创建或修改core/exceptions.py,定义ConfigError等异常类。 2. 确保core/config.py从.core.exceptions导入ConfigError。 3. 修改server.py的导入,使用get_config函数获取配置实例。 4. 修改server.py中所有使用SystemConfig的地方,改为使用get_config返回的实例。 由于原server.py代码没有提供,我们只能根据错误信息给出上述修改建议。 现在,我们先提供core/exceptions.py的代码,然后修改core/config.py的导入语句(已经正确则无需修改),最后修改server.py。 下面,我们写core/exceptions.py的代码。</think>根据错误日志,问题出在导入 `ConfigError` 时失败。这是因为在 `core/exceptions.py` 文件中缺少 `ConfigError` 类的定义。下面是完整的解决方案: ### 修复方案:完善异常处理模块 我们需要在 `core/exceptions.py` 文件中定义 `ConfigError` 异常类和其他必要的异常类。 ```python # E:\AI_System\core\exceptions.py """ 核心模块异常定义 """ class ConfigError(Exception): """配置相关的异常基类""" def __init__(self, message: str, config_key: Optional[str] = None): super().__init__(message) self.config_key = config_key self.message = message def __str__(self): if self.config_key: return f"配置错误: {self.message} (配置项: {self.config_key})" return f"配置错误: {self.message}" class InitializationError(Exception): """初始化异常""" def __init__(self, module_name: str, reason: str): super().__init__(f"模块 '{module_name}' 初始化失败: {reason}") self.module_name = module_name self.reason = reason class DependencyError(Exception): """依赖错误,如缺少必要模块""" def __init__(self, module_name: str, required_version: Optional[str] = None): msg = f"缺少必要依赖: {module_name}" if required_version: msg += f" (需要版本: {required_version}+)" super().__init__(msg) self.module_name = module_name self.required_version = required_version class SubsystemFailure(Exception): """子系统故障""" def __init__(self, subsystem_name: str, reason: str): super().__init__(f"子系统 '{subsystem_name}' 故障: {reason}") self.subsystem_name = subsystem_name self.reason = reason class ResourceLimitExceeded(Exception): """资源超限异常""" def __init__(self, resource_type: str, limit: Any, current: Any): super().__init__(f"{resource_type} 资源超限: 限制={limit}, 当前={current}") self.resource_type = resource_type self.limit = limit self.current = current class CircuitBreakerOpen(Exception): """熔断器开启状态异常""" def __init__(self, breaker_name: str, failure_count: int): super().__init__( f"熔断器 '{breaker_name}' 已开启 (失败次数: {failure_count})" ) self.breaker_name = breaker_name self.failure_count = failure_count class ValidationError(Exception): """数据验证失败异常""" def __init__(self, field_name: str, expected: str, actual: Any): super().__init__( f"字段 '{field_name}' 验证失败: 期望 {expected}, 实际 {actual}" ) self.field_name = field_name self.expected = expected self.actual = actual class TimeoutError(Exception): """操作超时异常""" def __init__(self, operation_name: str, timeout: float): super().__init__(f"操作 '{operation_name}' 超时 ({timeout}秒)") self.operation_name = operation_name self.timeout = timeout class CriticalSystemError(Exception): """关键系统错误,需要立即处理""" def __init__(self, component: str, error_code: int): super().__init__(f"关键系统错误 [{error_code}]: {component}") self.component = component self.error_code = error_code # 示例使用 if __name__ == "__main__": try: raise ConfigError("缺少必需配置项", "DATABASE_URL") except ConfigError as e: print(f"捕获到配置错误: {e}") try: raise ResourceLimitExceeded("内存", "4GB", "5.2GB") except ResourceLimitExceeded as e: print(f"资源超限: {e}") ``` ### 修改 `core/config.py` 的导入语句 ```python # E:\AI_System\core\config.py # ... 其他导入保持不变 ... from .exceptions import ConfigError # 确保从这里导入 class ConfigManager: # ... 类实现保持不变 ... ``` ### 修改 `core/__init__.py` 文件(如果存在) 确保 `core/__init__.py` 正确导出异常类: ```python # E:\AI_System\core\__init__.py from .exceptions import ( ConfigError, InitializationError, DependencyError, SubsystemFailure, ResourceLimitExceeded, CircuitBreakerOpen, ValidationError, TimeoutError, CriticalSystemError ) ``` ### 异常类的用途解释 1. **ConfigError**: - 专门处理配置相关的错误 - 包含出错的配置项名称 - 示例:`raise ConfigError("缺少必需配置项", "DATABASE_URL")` 2. **InitializationError**: - 系统初始化过程中发生的错误 - 记录初始化失败的模块和原因 - 示例:`raise InitializationError("数据库连接池", "连接超时")` 3. **DependencyError**: - 缺少必要依赖或版本不匹配 - 示例:`raise DependencyError("torch", "2.0+")` 4. **SubsystemFailure**: - 子系统运行中发生的故障 - 示例:`raise SubsystemFailure("内存管理", "内存泄漏")` 5. **ResourceLimitExceeded**: - 资源使用超出限制 - 示例:`raise ResourceLimitExceeded("CPU", 80, 95)` 6. **CircuitBreakerOpen**: - 熔断器开启状态下的操作尝试 - 示例:`raise CircuitBreakerOpen("API服务", 10)` 7. **ValidationError**: - 数据验证失败 - 示例:`raise ValidationError("email", "有效的邮箱地址", "invalid@")` 8. **TimeoutError**: - 操作超时 - 示例:`raise TimeoutError("数据库查询", 5.0)` 9. **CriticalSystemError**: - 需要立即处理的关键系统错误 - 包含错误代码 - 示例:`raise CriticalSystemError("核心调度器", 5001)` ### 在 `core/config.py` 中使用异常类 修改 `_validate_required_config` 方法,使用更详细的异常信息: ```python def _validate_required_config(self): """验证必需配置项是否存在""" required_keys = [ "MAX_WORKERS", "API_HOST", "API_PORT", "DB_PATH", "LOG_DIR", "LOG_LEVEL" ] missing_keys = [key for key in required_keys if key not in self.config] if missing_keys: error_msg = f"缺少必需配置项: {', '.join(missing_keys)}" self.logger.error(error_msg) # 使用更详细的异常信息 raise ConfigError( f"系统启动失败: 缺少 {len(missing_keys)} 个必需配置项", missing_keys[0] if missing_keys else None ) ``` ### 在 `server.py` 中处理异常 ```python # E:\AI_System\web_ui\server.py from core.exceptions import ConfigError, InitializationError try: # 初始化系统配置 from core.config import get_config system_config = get_config(base_dir="E:/AI_System") # 初始化其他系统组件... except ConfigError as e: logging.critical(f"关键配置错误: {e}") # 发送警报或采取其他恢复措施 exit(1) except InitializationError as e: logging.error(f"系统初始化失败: {e}") # 尝试回退到安全模式 fallback_to_safe_mode() ``` ### 测试验证 创建测试用例验证异常系统: ```python # tests/test_exceptions.py import unittest from core.exceptions import ConfigError, ResourceLimitExceeded class TestExceptions(unittest.TestCase): def test_config_error(self): with self.assertRaises(ConfigError) as cm: raise ConfigError("Missing required value", "API_PORT") ex = cm.exception self.assertEqual(ex.message, "Missing required value") self.assertEqual(ex.config_key, "API_PORT") self.assertIn("配置项: API_PORT", str(ex)) def test_resource_limit_exceeded(self): with self.assertRaises(ResourceLimitExceeded) as cm: raise ResourceLimitExceeded("Memory", "4GB", "5.2GB") ex = cm.exception self.assertEqual(ex.resource_type, "Memory") self.assertEqual(ex.limit, "4GB") self.assertEqual(ex.current, "5.2GB") self.assertIn("资源超限", str(ex)) if __name__ == '__main__': unittest.main() ``` ### 异常处理最佳实践 1. **层级化异常**: - 创建特定领域的异常类 - 避免使用过于通用的异常 2. **丰富上下文**: - 在异常中包含诊断信息 - 记录发生时的系统状态 3. **错误恢复**: - 区分可恢复和不可恢复错误 - 为可恢复错误提供恢复路径 4. **日志集成**: - 在捕获异常时记录详细日志 - 包含堆栈跟踪和关键变量值 5. **警报机制**: - 关键异常触发警报通知 - 区分不同严重级别的错误 6. **文档化异常**: - 为每个自定义异常编写文档 - 说明何时会抛出该异常 ### 修复后的预期效果 1. 解决 `ImportError` 错误:`ConfigError` 现在正确定义和导出 2. 增强错误处理:提供更丰富的异常类型用于不同场景 3. 提高系统健壮性:明确的异常类型有助于编写更精确的错误处理代码 4. 改善调试体验:详细的异常信息帮助快速定位问题根源 5. 统一错误处理:整个系统使用一致的异常处理模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值