pythonの開発環境

色々あってPythonの開発環境を立てようと思って調べたのだけど、ややこしかったので自分なりのまとめ。

現状のまとめとしては以下が一番わかりやすかったですね。
Rubyist が pyenv を使うときに知っておいてほしいこと - Qiita

現状の自分の結論的には

という感じです。

python3 + venv memo

% brew install python3
% python3 -m venv venv
% . venv/bin/activate
% pip freeze > requrements.txt
% pip install -r requrements.txt
% deactivate

venvのactivate/deactivateを自動でやる方法

はじめはdirenvを使って実現しようと思ったけど、directoryから出た時の動作が定義できないからうまくいかなそうとと思って調べたところ同じようにやろうとした人がいてつまづいてた。

direnvでvenv環境を自動でactivate — そこはかとなく書くよん。

とりあえずローカルで試してみたところ以下の環境であれ動くぞ...となったのだけど

zsh: 5.4.2
direnv: v2.13.1
python: 3.6.3

これはdirenvの.envrcがbash sub-shellから読まれるのとそこからの環境変数引き継ぎ周りが関係して
たまたま動いているように見えただけでdeactivateは見えないし闇な感じしかしない。
結果的に環境変数のexportだけだから、そのdirectoryから出ると正しく動いてそうに見えてしまう。

source does not work · Issue #268 · direnv/direnv · GitHub

そこから色々調べた結果、zsh使ってるなら以下を参考にzsh-autoenv使うのが
まぁよさそうかなーというところに落ち着きそうです

zsh-autoenvを使って、virtualenvの自動activate/deactivateを実現する - $shibayu36->blog;

Capistranoでデプロイ時に特定のファイルをデプロイ対象から外す

.gitattributesを用意して、

.gitattributes export-ignore
.gitignore export-ignore
spec/ export-ignore

のように記述します。

こうする事でdeploy対象外にすることができます。
これは、以下のp-rの通りdeployする際にgit archiveを使っているからです。

Use `git archive` to create release by seenmyfate · Pull Request #626 · capistrano/capistrano · GitHub

Railsでassetsのprecompile先を変更する

public/assetsにもともとコンテンツをおいてしまっていて、precompileしたものと衝突してしまったので。
いちばんいいのはもとからassets以下にはコンテンツをおかないように作ることだとは思う。

config/application.rbにて以下を指定。

  config.assets.prefix = '/app-assets'

あとはcapistranoでの設定。
config/deploy.rbで以下の二つを指定。

  set :assets_prefix, 'app-assets'

...

  set :linked_dirs, %w{... public/app-assets}

Capistrano 3でdeploy時にniceにassets:precompileする方法

config/deploy.rbに以下を書いた。

ただ、この方法だと全部のrake taskにniceが効いてしまうのでいまいち。問題はないけど。

namespace :assets do
    # clear action because Rake DSL on v3 is additive
    # refs) http://capistranorb.com/documentation/advanced-features/overriding-capistrano-tasks/
    Rake::Task['deploy:assets:precompile'].clear_actions
    task :precompile => [:map_nice] do
      on roles(fetch(:assets_roles)) do
        within release_path do
          with rails_env: fetch(:rails_env) do
            execute :rake, "assets:precompile"
          end
        end
      end
    end

    task :map_nice do
      SSHKit.config.command_map.prefix[:rake].unshift('nice -n 19')
    end

  end


あと書いてからから気づいたけど、deploy:assets:precompile自体は上書きせずに、beforeでmap_niceを実行するだけでよさそう。capistrano/rbenvがunshift, capistrano/bundlerがpushでコマンド追加していて、rbenv niceはエラーになるので評価タイミングはめんどう。

ちなみに、capistrano/*がcommand_mapを追加してるタイミングは以下。taskのhookだと複数回評価される可能性があるけど、以下のタイミングなら一度きり。なるほど。

Capistrano::DSL.stages.each do |stage|
  after stage, 'rbenv:map_bins'
end


という訳で追記内容は最終的にこうなった。

namespace :deploy do
  namespace :assets do
    task :map_bins  do
      SSHKit.config.command_map.prefix[:rake].unshift('nice -n 19')
    end

  end

end

Capistrano::DSL.stages.each do |stage|
  after stage, 'deploy:assets:map_bins'
end

Railsのdb:seedでcsvからデータをimportするやつ

を書いた。(db/seeds.rb)
あとはテーブル名.csvみたいなCSVファイルをseeds_dirに置けばrake db:seedでimportできる、というメモ。

seeds_dir  = "#{Rails.root}/db/seeds/#{Rails.env}"

csv_files = Dir.entries(seeds_dir).select {|f| f =~ /\.csv$/ }
csv_files.each do |csv_file|
  p "#{csv_file} from csv"

  model_name = File.basename(csv_file, '.csv')
  model      = model_name.classify.constantize

  path = "#{seeds_dir}/#{csv_file}"
  csv  = CSV.read(path, headers: true, converters: :numeric)
  ActiveRecord::Base.transaction do
    csv.each do |row|
      # idが重複するレコードがある場合はupdate
      if row.has_key?('id')
        record = model.where(id: row['id']).first
        if record.present?
          record.update(row.to_hash)
          next
        end
      end

      model.create(row.to_hash)
    end
  end
end