From Flaskl to Sanic, I encountered some problems during my study. I will try to make it clear and expect a series of articles to come out.
app.update_config()
With Flask, the following configuration classes are used in the tutorial:
# config.py import os class Config: BASE_DIR = os.path.dirname(os.path.dirname(__file__)) @staticmethod def init_app(app): pass class DevConfig(Config): DEBUG = True DB_URL = 'mysql://test:Tes@*.*.*.*:3306/test' class ProConfig(Config): DEBUG = False DB_URL = 'mysql://production:production@*.*.*.*:3306/production' config = { 'development': DevConfig, 'production': ProConfig, 'default': DevConfig }
Use it as follows:
app = Flask(__name__) app.config.from_object(DevConfig)
Different environments use different configurations, and some of the same configurations can be placed in the Config base class (such as BASE_DIR).
In anic, app.update_config() can also pass in a class, but unexpectedly:
app = Sanic(__name__) app.update_config(Devconfig) # BASE_DIR with no parent in the configuration at this time
Look at the code for update_config() in sanic, which gets attributes from u dict_u when the attributes of the parent class are unreadable:
def update_config(self, config: Union[bytes, str, dict, Any]): # config is a bytes,str,Path type of processing if isinstance(config, (bytes, str, Path)): config = load_module_from_file_location(location=config) # Whether it is an incoming class or an object, attributes are acquired through u dict_, and the attributes of its parent class are unreadable if not isinstance(config, dict): cfg = {} if not isclass(config): cfg.update( { key: getattr(config, key) for key in config.__class__.__dict__.keys() # Getting class attributes from u dict_u of the object's class } ) config = dict(config.__dict__) # Use u dict_u directly to get attributes config.update(cfg) config = dict(filter(lambda i: i[0].isupper(), config.items())) self.update(config)
flask's app.config.from_object() uses dir(object) to get attributes. It reads the attributes of the parent class, and then uses getattr(obj, key) to read the attribute values:
def from_object(self, obj): if isinstance(obj, string_types): obj = import_string(obj) for key in dir(obj): # Using dir(obj), the attributes of the parent class are also read out if key.isupper(): # Determine if the key is capitalized self[key] = getattr(obj, key)
The question arises whether to use u dict_ or dir(object). The differences between the two are as follows:
_u dict_u: View all the properties in the class, it is a dictionary.
- It is important to note that this property can be invoked with the class name or an instance object of the class, that a direct call to u dict_u with the class name will output the dictionary composed of all the class properties in the class, and that a call to u dict_u with the instance object of the class will output a dictionary composed of all the instance properties in the class.
- For parent and child classes with inheritance, the parent has its own u dict_u, and the child has its own u dict_u, which does not contain the parent's u dict_u.
dir() function: View a list of the names of all the properties and methods within the object.
- If dir: Returns the class attribute, method name.
- Dir (object): Returns class properties, instance properties, and method names.
How can I solve this problem?
- Referring to flask:
conf = config[config_name] app.update_config({key: getattr(conf, key) for key in dir(conf) if key.isupper()}) print(app.config.BASE_DIR)
- Add a class method to the base class Config and return its properties as a dictionary. Then use config_cls.to_dict() in app.update_config(). The difference is that before you passed in a config class, you now passed in a dictionary:
# config.py import os class Config: BASE_DIR = os.path.dirname(os.path.dirname(__file__)) @staticmethod def init_app(app): pass # Add a class method that returns all uppercase class properties of a class @classmethod def to_dict(cls): return {key: getattr(cls, key) for key in dir(cls) if key.isupper()} class DevConfig(Config): DEBUG = True ACCESS_LOG = False DB_URL = 'mysql://test:Tes@*.*.*.*:3306/test' class ProConfig(Config): DEBUG = False ACCESS_LOG = False DB_URL = 'mysql://production:production@*.*.*.*:3306/production' config = { 'development': DevConfig, 'production': ProConfig, 'default': DevConfig } # app.py from sanic import Sanic form config import config app = Sanic(__name__) conf_name = 'development' # Call the class method to_dict() of the config class app.update_config(config[conf_name].to_dict())
In addition, in sanic's update_config(), the isClass() method is used to determine whether a class or an object is passed in.
def isclass(object): return isinstance(object, type)
Simply use isinstance(). In python, [Everything is an object].
conf = DevConfig() print(isinstance(conf, object)) # True print(isinstance(conf(), object)) # True print(isinstance(conf, type)) # True print(isinstance(conf(), type)) # False
Conf, conf() are objects, but conf (class) is type, conf() (object) is not type.