CuriousY A world with wonder

在Github上构建Python项目CI的一些心得

| Comment

项目在此

CI服务选择了使用广泛的Travis CI,代码覆盖则交给了Coveralls,在项目页面显示badge用的是shields.io。因为关于怎么搭建各自站点的教程都很清楚,这里就不浪费时间了,只记录一些我当时搭建时碰到的一些问题以及这些问题是如何解决的。

Travis CI相关

  1. 既然直接列出多个元素,Travis CI就会自动启多个job,那matrix关键字有什么用?

    A: 很多情况下是用不上matrix的,但考虑这样一种情况:我想在Linux系统上测试Python 2.7和Python 3.6,而在OSX上只测试Python 2.7,就需要用matrix来列出所有的组合了:

    matrix:
      include:
      - os: linux
        python: "2.7"
      - os: linux
        python: "3.6"
      - os: osx
        python: "2.7"
    
  2. 在Travis CI上macOS下的Python环境启动失败,出现了类似“The command “sudo tar xjf python-2.7.tar.bz2 –directory /” failed and exited with 1 during .”的错误?

    A: Travis CI目前并不支持os: osx的情况下选择language: pythonhttps://github.com/travis-ci/travis-ci/issues/2312)。这里不支持的意思是macOS自带的Python不支持,当然你可以选择启动好VM后再安装指定版本的Python,并且很多项目也是这么做的。

  3. 为何OSX的job总是比较慢?

    A: 因为Linux默认情况下起来的是container,OSX只能启VM。

Read more

Inject python code before __main__ function

| Comment

I’m working on a project which needs to inject some initilize code before the __main__ function starts, i.e. running the following command and our injected code is executed before the target script executed.

python <target_script>

Solutions

There are many ways to implement above requirement. For example, we can hijack the python command using alias (Or just define a shell function called “python” and the effect is the same.):

alias python='python <my_inject_script>'

Then in my_inject_script, we can do the initialization and then execute the target script.

Another solution is using Python build-in site package:

This module is automatically imported during initialization.

So we can create a sitecustomize.py under the site package folder and this module will be automatically imported each time python command is executed.

Read more

React Native初窥

| Comment
  1. 类似于create-react-app,React Native也有一款用来快速创建项目的工具,叫create-react-native-app。使用该工具来初始化一个项目,你会发现项目比用create-react-app创建的还要简洁,查看package.json,里面的依赖除了reactreact-native,还有一个叫作expo的库。

  2. expo对手机端的一些API做了一些封装,从而可以使用JavaScript来调用这些API(比如打开照相机)。它的工作原理其实就是在原有API上添加了一个中间层,这个中间层(就是expo)来和底层的API打交道,而我们的代码只需要和中间层打交道即可。因此,不同的手机端系统上,expo的实现应该是不同的,但保证了应用层代码的一致性。

  3. 使用expo的话,在手机上必须要安装对应的app,在电脑上npm start之后扫打印出来的码就可以在手机上调试写的app了,非常的方便。当然,也可以用电脑上的手机模拟器来调试,不过需要安装Xcode(iOS)。它的工作原理是电脑端启动了一个http server,然后手机端作为client来下载代码并执行,所以电脑和手机必须要在同一个子网内才能工作。

  4. 使用create-react-native-app创建的项目的入口在App.js,但查看App.js却并不能看到类似register(App)之类的语句,而只是简单的export了一个React组件。似乎入口是App.js是被hard code的。查看package.json,可以看到这么一行:

      "main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
    

    其实这个文件才是真正的入口,继续查看该文件,可以看到:

    var _App = require('../../../../App');
    

    的确是hard code的,之所以要hard code是因为JavaScript目前不支持动态加载(see https://github.com/react-community/create-react-native-app/issues/152)。

    回想一下React的项目为什么没有这种限制,是因为它是用Webpack把所有后缀是jsjsx的文件打包起来了最后放到浏览器中一起执行,所以只要这其中某一个文件中包含一个入口即可。

Read more

Reading <Async & Performance> - 2

| Comment

Chapter 4: Generators

Breaking Run-to-Completion

Consider:

function *foo(x) {
	var y = x * (yield);
	return y;
}

var it = foo( 6 );

// start `foo(..)`
it.next();

var res = it.next( 7 );

res.value;		// 42

First, we pass in 6 as the parameter x. Then we call it.next(), and it starts up *foo(..).

Inside *foo(..), the var y = x .. statement starts to be processed, but then it runs across a yield expression. At that point, it pauses *foo(..) (in the middle of the assignment statement!), and essentially requests the calling code to provide a result value for the yield expression. Next, we call it.next( 7 ), which is passing the 7 value back in to be that result of the paused yield expression.

注意这里调用了两次next函数,第一次只是启动了生成器并到达了第一个yield语句(foo(6)只是定义了一个生成器,但还没有开始执行其中的代码),第二次输入yield的值并到达了最终的return语句。

这里还有一个比较tricky的地方在于JavaScript中生成器的next函数是可以有一个输入的,next函数有输入时,会用输入的值来替代整个yield表达式的值,没有输入时,其实相当于传入了undefined(作为对比,Python中生成器的next函数是不支持输入参数的)。比如:

function* bar() {
    var y = yield 2;
    return y;
}

var it = bar();

console.log(it.next());  // { value: 2, done: false }
console.log(it.next());  // { value: undefined, done: true }

// ==== give a input to next() ====
var it2 = bar();

console.log(it2.next());  // { value: 2, done: false }
console.log(it2.next(3));  // { value: 3, done: true }

因此,yield表达式可以用在赋值语句当中,并由next函数来动态决定其表达式的值。

Read more

Reading <Async & Performance> - 1

| Comment

Chapter 1: Asynchrony: Now & Later

Event Loop

So what is the event loop?

Let’s conceptualize it first through some fake-ish code:

// `eventLoop` is an array that acts as a queue (first-in, first-out)
var eventLoop = [ ];
var event;

// keep going "forever"
while (true) {
	// perform a "tick"
	if (eventLoop.length > 0) {
		// get the next event in the queue
		event = eventLoop.shift();

		// now, execute the next event
		try {
			event();
		}
		catch (err) {
			reportError(err);
		}
	}
}

It’s important to note that setTimeout(..) doesn’t put your callback on the event loop queue. What it does is set up a timer; when the timer expires, the environment places your callback into the event loop, such that some future tick will pick it up and execute it.

What if there are already 20 items in the event loop at that moment? Your callback waits. It gets in line behind the others – there’s not normally a path for preempting the queue and skipping ahead in line. This explains why setTimeout(..) timers may not fire with perfect temporal accuracy. You’re guaranteed (roughly speaking) that your callback won’t fire before the time interval you specify, but it can happen at or after that time, depending on the state of the event queue.

setTimeout函数是在一定时间之后将回调函数插入到event loop之中,但其并不保证插入之后便立即得到执行(取决于插入时event loop队列是否为空,比如setTimeout(..., 0)并不会在该语句执行完后就立刻执行,而是会在当前整段代码执行完成之后再执行,比如下面的代码)。

setTimeout(function () {
    console.log('A')
}, 0);

function demo() {
    setTimeout(function () {
        console.log('B');
    }, 0);
    console.log('C');
}

demo();
console.log('D');

最后输出的顺序是CDAB,即整块代码中同步的部分会先执行,然后再是异步的部分。或者这样理解,执行上面的代码块本身是一个是atomic task,两个setTimeout函数分别又创建了两个task,并安排在当前task执行完之后执行。


Because of JavaScript’s single-threading, the code inside of foo() (and bar()) is atomic, which means that once foo() starts running, the entirety of its code will finish before any of the code in bar() can run, or vice versa. This is called “run-to-completion” behavior.

Javascript是单线程的,所以在一个瞬间只有一段代码会被执行。而由于event loop的机制,所有插入其中的task都自带了原子属性,即一个task完全执行完才会去执行下一个task,即使这两个task被安排到了同一时间执行也是如此(安排在同一时间就按照进入event loop的先后来按顺序执行呗)。有点Python中协程的感觉。

Read more
| Page 6 of 25 |