dophon documentation

Thanks for the reminder from lemonwater, it needs to be explained at the beginning of the article

brief introduction:

This is a fast web service development framework based on flask server developed by python,

Some common functions required for integrated development, refer to object management in java and some ideas of instance injection,

There are also some optimization functions added later (such as request blacklist <--- preliminary concept, preventing high-frequency access) and the like

Recommended usage scenarios:

Used to solve some servers that require rapid development or low cost (I am considering integrating SpringCloud's sidecar)

Contact information:

If you have any questions or suggestions, please send an email to ---> [email protected]

Code cloud connection:

CookBook : Framework document (click to jump)


The new version (1.2.4 adds modular management, and the db module is initially split, which is not conducive to development on the ide. If you want the ide to have some module prompts, please use the full module, please use version 1.1.8)

This document is the 1.1.8 version document. The new version (1.2.4) has different module names. I will publish the document as soon as possible.


quick start

1. Introduce dophon

pip install dophon

2. Start the server

from dophon import boot

...

if '__main__' == __name__:

    boot.run_app()

3. Configuration file parameters

# dophon.properties.__init__.py

"""<div/>
配置集合<div/>
author:CallMeE<div/>
date:2018-06-01<div/>
"""

# 定义工程根目录(必须)
project_root=os.getcwd()

# 此处为服务器配置(必须,默认开启ssl)
host = '127.0.0.1'  # 服务器监听地址(全ip监听为0.0.0.0),默认监听本地
port = 443 # 服务器监听端口
ssl_context = 'adhoc' # ssl证书路径(默认本地证书)

# 此处为路由文件夹配置
blueprint_path = ['/routes'] # route model dir path(路由文件夹名称)

# 此处为数据库配置
pool_conn_num = 5 # size of db connect pool() # 数据库连接池连接数(默认5个)
pydc_host = 'localhost' # 数据库连接地址
pydc_port = 3306 # 数据库连接端口
pydc_user = 'username' # 数据库连接用户名
pydc_password = 'password' # 数据库连接密码
pydc_database = 'database' # 连接数据库名(可在后面跟连接参数)

4. Routing

Quick definition:

from dophon import boot

app = boot.get_app()

method one:

import dophon
import DemoClass

_DemoRou=None

app=dophon.blue_print(
    inject_config={
        'inj_obj_list': {
            '_DemoRou': DemoClass
        },
        'global_obj': globals()
    },  # 此处为自动注入参数配置(非必须,不需要请填入空字典)
    name='demo',  # 此处为路由代号(必须,不能重复)
    import_name=__name__  # 此处为路由初始化名称(必须,无特定需求填写__name__)
) 
  1. The app defined in method 1 is flask's Blueprint type routing, and it has its own instance injection function (inject_config parameter)
  2. The inject_config parameter is empty by default, that is, instance injection is not invoked
  3. The key of inj_obj_list in inject_config must be explicitly defined above (mainly for convenience of reading and writing)
  4. The rest of the parameters are the same as Blueprint in flask

Method two:

from flask import Blueprint

app=Blueprint('demo',__name__) # 具体参数参照flask.Blueprint
  1. The second way is to define a route directly using flask's Blueprint

5. Object Injection

5.1 Configuration injection

Method 1: Refer to <4. Routing. Method 1>

Method two:

from dophon import annotation
import class_1
import class_2

inject_prop={
    'obj_1':class_1.obj1,
    'obj_2':class_2.obj1
}

obj_1=None
obj_2=None

@Autowired.OuterWired(inject_prop,globals())
def inject_method():
    pass

inject_method()

Method 3 (not recommended):

from dophon import annotation

import class_1
import class_2

obj_1=None
obj_2=None

@Autowired.InnerWired([class_1.obj1,class_2.obj1],['obj_1','obj_2'],globals())
def inject_method():
 pass

inject_method()

ps: The injection configuration listed above can be managed by introducing external objects, that is, creating a file to achieve unified management of configuration by introducing variables in the file

5.2 Function decorator injection

5.2.1 Definition of Instance Manager

An instance manager must be defined before injection

from dophon.annotation import *

class OwnBeanConfig(BeanConfig):
    """
    实例管理器必须继承BeanConfig)
    
    注意!!!
        实例定义关键字必须唯一
    """
        
    # 方式一
    @bean()
    def demo_obj_1(self):
        """
        此处返回管理关键字为demo_obj_1的DemoObj()实例
        """
        return DemoObj()
        
    # 方式二
    @bean(name='Demo')
    def demo_obj_2(self):
        """
        此处返回管理关键字为Demo的DemoObj()实例
        """
        return DemoObj()

  • The instance manager supports the with syntax
with OwnBeanConfig() as config:
    pass
  • The instance manager can also be started using the normal instantiated instance start method
OwnBeanConfig()()  # 注意是两个括号

ps: It is recommended to use BeanConfig subclasses as instance batch management

5.2.2 Obtaining an instance

from dophon.annotation import *

bean=Bean('demo_obj_1')  # 此处获取管理关键字为demo_obj_1对应的实例

# 或者使用类来定位实例
bean=Bean(DemoObj)  # 多个同类实例会抛出语义错误

6. Other Notes

First introduce the annotation module

from dophon import annotation

or

from dophon.annotation import *

6.1 @ResponseBody

Return data in json format

from dophon.annotation import *

@ResponseBody()
def fun():
    return 'result'
    
# response -> result

@ResponseBody()
def fun():
    return {
    'message':'result'
    }
    
# response -> { 'message' : 'result' }

@ResponseBody()
def fun():
    result={
        'message':'result'
        }
    return result
    
# response -> { 'message' : 'result' }

6.2 @ResponseTemplate

Return to the corresponding page (html file in the default routing directory)


from dophon.annotation import *

@ResponseTemplate('index.html')
def ...

ps: For additional management page paths, please configure template_folder in the route definition (dophon.blue_print()), following the cd path syntax of the Linux system

6.3 @AutoParam

Parameters in the automatic configuration request (separated form) It is recommended to specify the list of kwarg_list parameters in the decorator (that is, the list form of formal parameters), otherwise there will be parameter confusion (severe)

from dophon.annotation import *

@AutoParam(kwarg_list=['param_1','param_2','param_3'])
def fun(param_1,param_2,param_3):
    print(param_1)
    print(param_2)
    print(param_3)

# request -> (params){ 'param_1' : '1' , 'param_2' : '2' , 'param_3' : '3' }
# console -> 1
#            2
#            3

Due to the confusion of parameters in this decorator, it is recommended to use the FullParam parameter decorator (below)

6.4 @FullParam

The parameters in the automatic configuration request (centralized form) are expressed in the form of dict. There is no name requirement for assignment parameters, and the first parameter in the default assignment parameter list

from dophon.annotation import *

@FullParam()
def fun(args):
    print(args)

# request -> (params){ 'param_1' : '1' , 'param_2' : '2' , 'param_3' : '3' }
# console -> { 'param_1' : '1' , 'param_2' : '2' , 'param_3' : '3' }

6.5 @RequestMapping

Simplified routing (same as app.route())

from dophon.annotation import *
from dophon import boot

app=boot.get_app()

@RequestMapping(app=app,'/test',['get'])
def fun():
    pass

6.5 @Autowired

Refer to <5. Object Injection>

from dophon.annotation import *

@AutoWired()
def fun():
    pass

7. Log module (based on logging module in python)

7.1 Log module reference

from dophon import logger

logger.inject_logger(globals())

Among them: globals() is the variable domain injected into the logging function, which can be a local variable domain, a local variable domain, or a custom variable management domain

7.2 Use of log module

Console with color output (slightly ugly)

The log output format is as follows:

'%(levelname)s : (%(asctime)s) ==> ::: %(message)s'

E.g:

INFO : (2018-08-02 15:34:11) ==> ::: 执行批量实例管理初始化

7.2.0 Custom log configuration:

The format code is as follows:

  • %(levelno)s: print the value of the log level<br/>
  • %(levelname)s: print the name of the log level<br/>
  • %(pathname)s: Print the path of the currently executing program, which is actually sys.argv[0]<br/>
  • %(filename)s: print the name of the currently executing program<br/>
  • %(funcName)s: The current function to print the log<br/>
  • %(lineno)d: print the current line number of the log<br/>
  • %(asctime)s: the time to print the log<br/>
  • %(thread)d: print thread ID<br/>
  • %(threadName)s: print thread name<br/>
  • %(process)d: print process ID<br/>
  • %(message)s: print log information<br/>

Define the logging configuration via a custom configuration file (application.py):

# 此处为日志配置
logger_config={
    # 'filename': 'app.log',
    # 'level': 'logging.DEBUG',
    'format': '%(levelname)s : <%(module)s> (%(asctime)s) ==> %(filename)s {%(funcName)s} [line:%(lineno)d] ::: %(message)s',
    'datefmt': '%Y-%m-%d %H:%M:%S'
}

7.2.1 debug:

7.2.2 info:

7.2.3 warning:

7.2.4 error:

7.2.5 critical:

8. Message queue

  1. Just a lightweight message queue with medium carrying capacity
  2. Even if the thread pool is used to process messages, it consumes cpu resources (GIL) extremely
  3. The queue is persisted based on io as a message, and high-frequency messages can easily cause io to block.
  4. Message consumption defaults to 1-3 seconds delay (local)

8.1 Configuration

// The upper limit of the message queue single machine is recommended 30-50 topics (tags)

The above sentence has no meaning. In subsequent versions (1.18+), the automatic scaling of the ruler capacity is carried out through the thread pool (the default coefficient is 2) that encapsulates the elastic capacity.

Configurable upper limit via custom configuration

<application.py>

msg_queue_max_num = 30   # 消息队列线程池承载上限

8.2 Producer Configuration

It is recommended to pass data in json format (convenient for consumers to escape data)

from dophon.msg_queue import *

@producer(tag='DEMO_TAG')
def producer():
    return 'aaa'

8.3 Consumer Configuration

method one:

from dophon.msg_queue import *

@consumer(tag='DEMO_TAG')
def consumer(args):
    print(args)
consumer()

# ERROR : (2018-08-02 21:29:15) ==> ::: 2018080221291454499310002: consume() argument after ** must be a mapping, not str

Non-json will report an error, you need to open as_arg on the decorator

from dophon.msg_queue import *

@consumer(tag='DEMO_TAG',as_args=True)
def consumer(args):
    print(args)
consumer()

# aaa

8.4 Unified management of consumers

from dophon.msg_queue import *

class TestConsumer(Consumer):

    @consumer(tag='test_msg_tag|test_msg_tag2', as_args=False, delay=1)
    def consume_msg(msg, timestamp, tag):
        print(msg)
        print(timestamp)
        print(tag)

# 实例化衍生类启动消费者
TestConsumer()

9. Database interaction

9.0 Configuration related

9.1 Result set mapping method

Result set: a collection of SQL execution scripts, because most of the queries in actual development, referred to as the result set

A number of result sets are specified by xml files

<!--test.xml-->
<select id="findAll">
    SELECT
    *
    FROM
    table
</select>

Associate the xml file by code and initialize the result set

from dophon.mysql import *

_cursor=db_obj('/test.xml',auto_fix=True)

# 根路径为配置文件路径
# 文件路径必须以/开头

Get one of the result sets in the xml file through the code (distinguished by id)

result= _cursor.exe_sql(methodName='findAll')

Support dynamic parameter input (#{} form) and skeleton parameter input (${form})

Dynamic parameters passed in:

<select id="findAllById">
    SELECT
    *
    FROM
    table
    WHERE
    id=#{id}
</select>
result= _cursor.exe_sql(methodName='findAll',args={'id':'12345678'})

Skeleton parameters passed in:

<select id="findAllByTableName">
    SELECT
    *
    FROM
    ${table_name}
</select>
result= _cursor.exe_sql(methodName='findAll',args={'id':'12345678'})

Support single query, list query, queue query (list form and dictionary form of result set id and parameter list)

Single query:

result= _cursor.exe_sql_single(methodName='findAll',args={'id':'12345678'})


# result<dict>

List query:

result= _cursor.exe_sql(methodName='findAll',args={'id':'12345678'})

# result<list>

Queue query (unstable):

1. List form:

result= _cursor.exe_sql_queue(
    method_queue=['test1','test2'],
    args_queue=[
        {'id':'123456','name':'tom'},
        {}
    ]
)

# result<dict>
# {
#   method_name:exec_result
# }

2. Dictionary form:

result= _cursor.exe_sql_obj_queue(
    queue_obj={
        'test1':{
            'id':'123456'
        },
        'test2':{}
    }
)

# result<dict>
# {
#   method_name:exec_result
# }

Support result set file hot update

update_round(_cursor,1)

# update_round(<cursor>,second:int)

Supports remote maintenance of result set files

remote_cell = remote.getCell('test.xml', remote_path='http://127.0.0.1:8400/member/export/xml/test.xml')
_cursor = db_obj(remote_cell.getPath(), debug=True)
或者
_cursor = db_obj(remote_cell, debug=True)

9.2 Table Model Mapping Method

Temporarily support single transaction operation

Get the database table mapping skeleton by initializing the model manager

from dophon import orm
manager = orm.init_orm_manager(['user'])

Get the table operation cache instance (operation instance) by instantiating the mapping skeleton

user = manager.user()

Simulate the corresponding table operation by assigning the operation instance

print('打印对象变量域')
for attr in dir(user):
    print(attr, ":", eval("user." + attr))
print('开始对对象赋值')
user.user_id = 'id'
user.info_id = 'info_id'
user.user_name = 'user_name'
user.user_pwd = 'user_pwd'
user.user_status = 123
user.create_time = datetime.datetime.now().strftime('%y-%m-%d')
user.update_time = datetime.datetime.now().strftime('%y-%m-%d')
print('对象赋值完毕')
print('打印对象变量域')
for attr in dir(user):
    print(attr, ":", eval("user." + attr))
print('打印对象参数表')
print(user([]))

print('user([]):', user([]))
print("user(['user_id','info_id']):", user(['user_id', 'info_id']))
print("user.get_field_list():", user.get_field_list())
print("user.alias('user_table').get_field_list():", user.alias('user_table').get_field_list())



Perform data landing operations on the corresponding table structure of the database by structuring the operation instance

print(user.where())
print(user.values())

user.select()
user.user_name = '111'
user.select_one()
user.select_all()

user = manager.user()
user.alias('u').select()
user.user_name = '111'
user.alias('us').select_one()
user.alias('userr').select_all()


user.user_id='test_id'
user.info_id='test_info_id'
user.user_name='test_user_name'
user.user_pwd='test_user_pwd'
user.user_status=1
user.create_time = datetime.datetime.now().strftime('%y-%m-%d')
user.update_time = datetime.datetime.now().strftime('%y-%m-%d')

print(user.insert())
#
user.user_id = 'test_id'
user.info_id = 'info_id'
user.user_name = '柯李艺'
user.user_pwd = '333'
user.user_status = 123
print(user.update(update=['user_name','user_pwd'],where=['user_id']))
#
user.user_id = 'test_id'
user.info_id = 'info_id'
user.user_name = 'user_name'
user.user_pwd = 'user_pwd'
user.user_status = 123
print(user.delete(where=['user_id']))

user1=manager.user()
user2=manager.user()
print(user1.select())
user1.user_name='early'
user1.left_join(user2,['user_id'],['user_id'])
user1.alias('u1').left_join(user2.alias('u2'),['user_id'],['user_id'])
# print(user1.exe_join())
print(user1.select())

user1 = manager.user()
print('user1', '---', id(user1))
user2 = user1.copy_to_obj(manager.user)
print('user2', '---', id(user2))
print(user1('user_id'))
user3 = user1.read_from_dict({
    'user_id': '111'
})
print('user3', '---', id(user3))
print(user1('user_id'))
print(user3('user_id'))

10. Container startup

Framework container startup function:<br/>

  1. Implement automatic generation of deployment containers
  2. Automatically install project related dependencies
  3. Development IDE console debugging

Framework dependent container: docker (click to go to the official website)

Code:

# coding: utf-8"
from dophon import docker_boot

docker_boot.run_as_docker()
  • operation result:
INFO : (2018-08-14 12:10:14) ==> ::: 容器前期准备
INFO : (2018-08-14 12:10:14) ==> ::: 生成依赖文件
INFO : (2018-08-14 12:10:17) ==> ::: 生成Dockerfile
INFO : (2018-08-14 12:10:17) ==> ::: 暂停已运行的实例
demo
INFO : (2018-08-14 12:10:28) ==> ::: 移除已运行的实例
demo
INFO : (2018-08-14 12:10:29) ==> ::: 移除旧镜像
Untagged: demo:latest
Deleted: sha256:eb9ace16ac18eea033b87a4bcab0925dc0139664193e480796b00bff72ac132c
Deleted: sha256:2a1af90ac889f36ce7b2861cd8a0f9efa3a98c31915e965cb0bfd7887c32cb05
Deleted: sha256:42bf2fedac374e453deaf06c62643679e8b71de52835a71b228966330b2e90ab
INFO : (2018-08-14 12:10:30) ==> ::: 检测配置合法性
INFO : (2018-08-14 12:10:31) ==> ::: 建立镜像
Sending build context to Docker daemon  26.62kB
Step 1/6 : FROM python:3.6.5
 ---> 9a58cce9b09f
Step 2/6 : ADD . ./demo
 ---> 2b30f0d25df8
Step 3/6 : ADD . ./demo/demo
 ---> 61c751581940
Step 4/6 : WORKDIR ./demo
Removing intermediate container f9439713ab6f
 ---> 8ac1423c208b
Step 5/6 : RUN pip install -r requirements.txt
 ---> Running in 60b5364841ee
Collecting click==6.7 (from -r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/34/c1/8806f99713ddb993c5366c362b2f908f18269f8d792aff1abfd700775a77/click-6.7-py2.py3-none-any.whl (71kB)
Collecting dophon==1.1.7 (from -r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/98/81/33d06b15b37ef0715308a764c1cbf7a53ab69000d2bf7f029365b1c760cd/dophon-1.1.7-py3-none-any.whl (59kB)
Collecting Flask==1.0.2 (from -r requirements.txt (line 3))
  Downloading https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl (91kB)
Collecting itsdangerous==0.24 (from -r requirements.txt (line 4))
  Downloading https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz (46kB)
Collecting Jinja2==2.10 (from -r requirements.txt (line 5))
  Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB)
Collecting MarkupSafe==1.0 (from -r requirements.txt (line 6))
  Downloading https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz
Collecting six==1.11.0 (from -r requirements.txt (line 7))
  Downloading https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl
Collecting Werkzeug==0.14.1 (from -r requirements.txt (line 8))
  Downloading https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl (322kB)
Collecting PyMySQL>=0.9.0 (from dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/a7/7d/682c4a7da195a678047c8f1c51bb7682aaedee1dca7547883c3993ca9282/PyMySQL-0.9.2-py2.py3-none-any.whl (47kB)
Collecting urllib3>=1.23 (from dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/bd/c9/6fdd990019071a4a32a5e7cb78a1d92c53851ef4f56f62a3486e6a7d8ffb/urllib3-1.23-py2.py3-none-any.whl (133kB)
Collecting Flask-Bootstrap>=3.3.7.1 (from dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/88/53/958ce7c2aa26280b7fd7f3eecbf13053f1302ee2acb1db58ef32e1c23c2a/Flask-Bootstrap-3.3.7.1.tar.gz (456kB)
Collecting schedule>=0.5.0 (from dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/df/2c/3a94d846682a4fb94966e65bca19a1acb6f7dd85977f4e4cece6e677b757/schedule-0.5.0-py2.py3-none-any.whl
Collecting pyOpenSSL>=18.0.0 (from dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/96/af/9d29e6bd40823061aea2e0574ccb2fcf72bfd6130ce53d32773ec375458c/pyOpenSSL-18.0.0-py2.py3-none-any.whl (53kB)
Collecting gevent>=1.3.5 (from dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/b6/2b/6be042be1023df54889d9e2a90b167f6fea65445384fccfdfd988cc16239/gevent-1.3.5-cp36-cp36m-manylinux1_x86_64.whl (4.6MB)
Collecting cryptography (from PyMySQL>=0.9.0->dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/c2/fa/fa9a8933c285895935d1392922fe721e9cb1b2c1881d14f149213a227ee3/cryptography-2.3-cp34-abi3-manylinux1_x86_64.whl (2.1MB)
Collecting dominate (from Flask-Bootstrap>=3.3.7.1->dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/43/b2/3b7d67dd59dab93ae08569384b254323516e8868b453eea5614a53835baf/dominate-2.3.1.tar.gz
Collecting visitor (from Flask-Bootstrap>=3.3.7.1->dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/d7/58/785fcd6de4210049da5fafe62301b197f044f3835393594be368547142b0/visitor-0.1.3.tar.gz
Collecting greenlet>=0.4.13; platform_python_implementation == "CPython" (from gevent>=1.3.5->dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/de/7b/cb662640540725deb0627264f6b890ee2b7725848b8cbca49e27bf3273c6/greenlet-0.4.14-cp36-cp36m-manylinux1_x86_64.whl (41kB)
Collecting asn1crypto>=0.21.0 (from cryptography->PyMySQL>=0.9.0->dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/ea/cd/35485615f45f30a510576f1a56d1e0a7ad7bd8ab5ed7cdc600ef7cd06222/asn1crypto-0.24.0-py2.py3-none-any.whl (101kB)
Collecting idna>=2.1 (from cryptography->PyMySQL>=0.9.0->dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl (58kB)
Collecting cffi!=1.11.3,>=1.7 (from cryptography->PyMySQL>=0.9.0->dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/6d/c0/47db8f624f3e4e2f3f27be03a93379d1ba16a1450a7b1aacfa0366e2c0dd/cffi-1.11.5-cp36-cp36m-manylinux1_x86_64.whl (421kB)
Collecting pycparser (from cffi!=1.11.3,>=1.7->cryptography->PyMySQL>=0.9.0->dophon==1.1.7->-r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/8c/2d/aad7f16146f4197a11f8e91fb81df177adcc2073d36a17b1491fd09df6ed/pycparser-2.18.tar.gz (245kB)
Building wheels for collected packages: itsdangerous, MarkupSafe, Flask-Bootstrap, dominate, visitor, pycparser
  Running setup.py bdist_wheel for itsdangerous: started
  Running setup.py bdist_wheel for itsdangerous: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/2c/4a/61/5599631c1554768c6290b08c02c72d7317910374ca602ff1e5
  Running setup.py bdist_wheel for MarkupSafe: started
  Running setup.py bdist_wheel for MarkupSafe: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/33/56/20/ebe49a5c612fffe1c5a632146b16596f9e64676768661e4e46
  Running setup.py bdist_wheel for Flask-Bootstrap: started
  Running setup.py bdist_wheel for Flask-Bootstrap: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/e8/b9/93/ef6ac3b8ead2d72cbcc042b9d58b613aaf47e533b9dc5b5999
  Running setup.py bdist_wheel for dominate: started
  Running setup.py bdist_wheel for dominate: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/86/7c/76/a514f343c9e4f85f4c98fe13138ab9c8f756647155c4c1f25e
  Running setup.py bdist_wheel for visitor: started
  Running setup.py bdist_wheel for visitor: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/68/b0/a2/cc8c7cf94ca3d1088a7d2e27936c1e0da170e05f560973e8dd
  Running setup.py bdist_wheel for pycparser: started
  Running setup.py bdist_wheel for pycparser: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/c0/a1/27/5ba234bd77ea5a290cbf6d675259ec52293193467a12ef1f46
Successfully built itsdangerous MarkupSafe Flask-Bootstrap dominate visitor pycparser
Installing collected packages: click, MarkupSafe, Jinja2, itsdangerous, Werkzeug, Flask, six, asn1crypto, idna, pycparser, cffi, cryptography, PyMySQL, urllib3, dominate, visitor, Flask-Bootstrap, schedule, pyOpenSSL, greenlet, gevent, dophon
Successfully installed Flask-1.0.2 Flask-Bootstrap-3.3.7.1 Jinja2-2.10 MarkupSafe-1.0 PyMySQL-0.9.2 Werkzeug-0.14.1 asn1crypto-0.24.0 cffi-1.11.5 click-6.7 cryptography-2.3 dominate-2.3.1 dophon-1.1.7 gevent-1.3.5 greenlet-0.4.14 idna-2.7 itsdangerous-0.24 pyOpenSSL-18.0.0 pycparser-2.18 schedule-0.5.0 six-1.11.0 urllib3-1.23 visitor-0.1.3
You are using pip version 10.0.1, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Removing intermediate container 60b5364841ee
 ---> 4f7f51326068
Step 6/6 : CMD ["python","./Bootstrap.py"]
 ---> Running in a01240a5675c
Removing intermediate container a01240a5675c
 ---> 7fe9614a4948
Successfully built 7fe9614a4948
Successfully tagged demo:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
INFO : (2018-08-14 12:11:04) ==> ::: 运行镜像
6686125b7b5ccef21240181bc08da3aabbf0765b72d4ae404d2cc15aabbd0999
INFO : (2018-08-14 12:11:06) ==> ::: 打印容器内部地址(空地址代表启动失败)
'172.17.0.2'
INFO : (2018-08-14 12:11:07) ==> ::: 打印容器载体地址
10.10.75.1
INFO : (2018-08-14 12:11:07) ==> ::: 启动检测容器端口
INFO : (2018-08-14 12:11:07) ==> ::: 容器启动完毕
INFO : (2018-08-14 12:12:17) ==> ::: 容器存活性检查:http://10.10.75.1:80
INFO : (2018-08-14 12:12:27) ==> ::: 容器存活性检查:http://10.10.75.1:80
INFO : (2018-08-14 12:12:38) ==> ::: 容器存活性检查:http://10.10.75.1:80
{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324033495&siteId=291194637