I have list [True, False, False, True] and another list [1, 2, 3, 4] and a use case where I want to filter list 2 based on list 1 to remove values that line up with the element False in list 1…. so the outcome will be [1, 4]. list(compress(list2, list1)) will do it. As long as you can create a mask for the filter than itertool.compress will be your friend!
Quick tips and learnings
TL;DR
As the nextcloud docs say… if you want to write to an external volume that
location has to be writeable by the user/group www-data on the host system…
so if that makes sense to you then this TIL probably isn’t a ton of value.. if
not however, read on :)
Case Study
You want to self-host your own cloud and use a smart file system for convenience… Nextcloud and ZFS are pretty common goto answers for each of those problems.
My home NAS is built on ZFS and among other things I have a zpool named
tank and nested in there is a tank/nas dataset with several child zfs
datasets under that.
I want to use nextcloud mainly for auto-uploading photos from my wife’s and my phones for automatic backups.
The issue is that the nextcloud application (I run in Docker) is fixed as the
www-data user and so any volume/folder that you want nextcloud to write to
needs to be permissioned such that www-data owns it… but I don’t want
www-data to own everything in my NAS… so what’s a girl to do?
Solution
Well, one way to go is to just utilize docker volumes, write the data in the
container to /var/www/html and let that be the place your data backsup to.
I still wanted nextcloud to automatically write right to my NAS so I created a
nextcloud-upload directory inside of tank/nas/media/photos (photos cause
that’s all that gets automatically uploaded)
Then I chown -R www-data:www-data /tank/nas/media/photos/nextcloud-upload so
that just that sub-folder is owned by www-data. Now everyone’s happy!
In vim G clog % does a git clog {current file}. You get every commit that the target file is apart of (so there might be info in those commits unrelated)
As I was cleaning up my NAS recently I noticed that I ran out of storage even though my disk usage looked pretty low… turns out I was keeping a mega-ton of ZFS snapshots and due to my own ignorance at the time didn’t realize the storage cost of this!
zfs list-o space tank/home will show the disk usage of the dataset and snapshots in tank/home
From my daily driver Ubuntu machine I often open nautilus, dolphin, etc. and delete a file here or there on my NAS… turns out Ubuntu sends thse file to .Trash-100 ON THE NAS so I’m effectively just moving that file and not freeing up any space…
I started my homelab journey being super naive about ZFS and how to manage the
filesystem… that bit me in the butt when transfering a ton of files out of
folders and into datasets because ZFS is copy on write so I was essentially
duplicating my storage until I got a hair smarter about removing files after
they’re moved (rsync –remove-source-file ftw). But I had a ton of snapshots of
child datasets with a ton of data that I just never will need, so I learned
zfs list -H -o name -t snapshot tank/dataset1/dataset2 will list just the
snapshots for dataset2 and if you pipe that into xargs -n1 zfs destroy then
you have a way to clear out some snapshots you don’t need!
:PlugSnapshot, :w ~/dotfiles/nvim/snapshot.vim… keep your config safe with git!
I’ve had Plug 'hrsh7th/cmp-path' in my plugins for ever but didn’t notice
until recently that I wasn’t getting any filepath completion in vim!
Fuller setup instructions below the TLDR
TL;DR
Turns out I need to not be a dope and configure nvim-cmp to actually use it…
local cmp = require'cmp'
cmp.setup({
-- removed rest of setup - see the rest in my dotfiles
sources = cmp.config.sources({
{ name = 'path' }, -- This needs to be here!
})
})
My Setup
For the sake of completeness here is how I currently (May 2022) configure completion in Neovim usin nvim-cmp
Plugins #
I keep all my plugins in plugins.vim
call plug#begin(s:plug_dir)
Plug 'neovim/nvim-lspconfig'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/cmp-buffer'
Plug 'hrsh7th/cmp-path'
Plug 'hrsh7th/cmp-cmdline'
Plug 'hrsh7th/nvim-cmp'
" For ultisnips users.
<!-- " Plug 'SirVer/ultisnips' -->
<!-- " Plug 'quangnguyen30192/cmp-nvim-ultisnips' -->
call plug#end()
Vim Settings #
My vim settings are also kept in their own file, settings.vim
set completeopt=menu,menuone,noselect
nvim-cmp configuration #
I have a cmp.lua file that gets sourced in init.lua (file structure explained below) for configuring cmp.
-- Setup nvim-cmp.
local cmp = require'cmp'
cmp.setup({
snippet = {
-- REQUIRED - you must specify a snippet engine
expand = function(args)
-- For `ultisnips` user.
vim.fn["UltiSnips#Anon"](args.body)
end,
},
window = {
completion = cmp.config.window.bordered(),
},
mapping = {
['<Down>'] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }),
['<Up>'] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }),
['<C-d>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-Space>'] = cmp.mapping.complete(),
['<C-e>'] = cmp.mapping.close(),
['<Tab>'] = cmp.mapping(cmp.mapping.select_next_item(), { 'i', 's' }),
['<CR>'] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true,
})
},
sources = cmp.config.sources({
{ name = 'nvim_lsp' },
{ name = 'ultisnips' },
{ name = 'buffer' },
{ name = 'path' },
{ name = 'tmux' },
})
})
The sources section is what was key for this post…
Piecing it together!
My init.vim sources plugins and then settings and then finally calls init.lua.
init.lua sources my cmp.lua file and BANG! auto-completion.
More sources #
hrsh7th’s wiki for nvim-cmp is here and has example configs as well as a list of sources…
Don’t forget to configure and not just install!
I just started using FastAPI for a home project and needed to pass back a dynamic number of values from a form rendered with jinja…
Dynamic Values
The jinja templating for rendering HTML based on something like a python iterable is nice and easy
data is the result of a database query, and item is each row, so the dot notation is the value of each column basically in that row
<form method="post">
{% for item in data %}
<div class="form-check ">
<input class="form-check-input" name="item_{{ item.id }}" id="{{ item.name }}" value="{{ item.id }}" type="checkbox">
<label class="form-check-label" for="{{ item.id }}" > Label for: {{ item.name }} </label>
</div>
{% endfor %}
<button type="submit" class="submit btn btn-xl btn-outline-danger" >Remove</button>
</form>
This form generates a row with a checkbox for every item in data (in my
case each item is an existing row in my table). it?
The way to pass back all those values is pretty straight forward (after hours of messing around that is!)
# I hate it when tutorials don't show ALL relevant pieces to the blurb
import starlette.status as status
from fastapi import APIRouter, Depends, Form, Request
from fastapi.encoders import jsonable_encoder
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from app.session.session import create_get_session
router = APIRouter()
templates = Jinja2Templates(directory="templates/")
@router.post("/my_route/do_something_with_form", response_class=HTMLResponse)
async def delete_rows(
request: Request,
db: Session = Depends(create_get_session),
):
form_data = await request.get_form()
data = jsonable_encoder(form_data)
# data = {"item_1": 1, "item_2": 2, ... "item_N": N}
return RedirectResponse("/", status_code=status.HTTP_302_FOUND)
We await request.get_form() and after encoding the data we get a dictionary with key/value pairs of the name/value from the form!
This took me quite a long time to figure out in part because most of the Google-able resources are still on Flask…
If you use vim-plug for managing your vim plugins, do yourself a favor and snapshot your plugins before upgrading!
:PlugSnapshot creates a vim.snapshot file that you can use to restore your plugin versions with vim -S snapshot.vim
The snapshot file looks like this:
❯ cat snapshot.vim
" Generated by vim-plug
" Tue 17 May 2022 03:44:29 PM CDT
" :source this file in vim to restore the snapshot
" or execute: vim -S snapshot.vim
silent! let g:plugs['Telegraph.nvim'].commit = '92e472f4e83acd60eb3766168e66d02718bfefe0'
silent! let g:plugs['TrueZen.nvim'].commit = '508b977d71650da5c9243698614a9a1416f116d4'
silent! let g:plugs['ariake-vim-colors'].commit = '9fb35f1255e475631c9df24ecc5485a40360cc7b'
silent! let g:plugs['auto-pairs'].commit = '39f06b873a8449af8ff6a3eee716d3da14d63a76'
silent! let g:plugs['bufutils.vim'].commit = '4634feb1312fd73fab66cfaa860e7af3abde935b'
silent! let g:plugs['cmp-buffer'].commit = '12463cfcd9b14052f9effccbf1d84caa7a2d57f0'
silent! let g:plugs['cmp-cmdline'].commit = 'c36ca4bc1dedb12b4ba6546b96c43896fd6e7252'
silent! let g:plugs['cmp-nvim-lsp'].commit = 'e6b5feb2e6560b61f31c756fb9231a0d7b10c73d'
silent! let g:plugs['cmp-nvim-ultisnips'].commit = '21f02b62deb409ce69928a23406076bd0043ddbc'
silent! let g:plugs['cmp-path'].commit = '466b6b8270f7ba89abd59f402c73f63c7331ff6e'
silent! let g:plugs['cmp-spell'].commit = '5602f1a0de7831f8dad5b0c6db45328fbd539971'
silent! let g:plugs['compe-tabnine'].commit = '33e4af509c27da9ef2c9c3002c01e3ec031797d4'
silent! let g:plugs['coverage-highlight.vim'].commit = '864e03679ea4168661501246147893cc82020917'
silent! let g:plugs['diffurcate.vim'].commit = 'b804675072220ff7c7ebcd24a028aa4aa35f09cc'
silent! let g:plugs['fzf'].commit = '6dcf5c3d7d6c321b17e6a5673f1533d6e8350462'
silent! let g:plugs['fzf.vim'].commit = 'd5f1f8641b24c0fd5b10a299824362a2a1b20ae0'
silent! let g:plugs['git-blame.vim'].commit = '9d144b7bed5d8f1c9259551768b7f3b3d1294917'
silent! let g:plugs['harpoon'].commit = 'd3d3d22b6207f46f8ca64946f4d781e975aec0fc'
silent! let g:plugs['instant.nvim'].commit = 'c02d72267b12130609b7ad39b76cf7f4a3bc9554'
silent! let g:plugs['lsp-colors.nvim'].commit = '517fe3ab6b63f9907b093bc9443ef06b56f804f3'
silent! let g:plugs['lsp_extensions.nvim'].commit = '4011f4aec61ba59c734f5dbf52e91f258b99d985'
silent! let g:plugs['lspkind-nvim'].commit = '57e5b5dfbe991151b07d272a06e365a77cc3d0e7'
silent! let g:plugs['lspsaga.nvim'].commit = '8dde091a61ab07f639baaa82b456d3508d0aa7e8'
silent! let g:plugs['neoformat'].commit = '409ebbba9f4b568ea87ab4f2de90a645cf5d000a'
silent! let g:plugs['neovim-fuzzy'].commit = '0bef4e1a81c65fc05d31380dd74454bd67733837'
silent! let g:plugs['nerdtree'].commit = 'eed488b1cd1867bd25f19f90e10440c5cc7d6424'
silent! let g:plugs['nerdtree-visual-selection'].commit = '05427635ff053a2c542fcf8d7c3744c72575e76c'
silent! let g:plugs['nvim-cmp'].commit = 'a226b6a4ff72e5e809ed17734318233fb25c87f3'
silent! let g:plugs['nvim-compe'].commit = 'd186d739c54823e0b010feb205c6f97792322c08'
silent! let g:plugs['nvim-lspconfig'].commit = '9ff2a06cebd4c8c3af5259d713959ab310125bec'
silent! let g:plugs['nvim-lspinstall'].commit = '79ec2425d6b39cdcb69d379f3e56847f49be73eb'
silent! let g:plugs['nvim-treesitter'].commit = '10d57b3ec14cac0b6b759e1eb5594617b8a7e883'
silent! let g:plugs['nvim-treesitter-textobjects'].commit = '094e8ad3cc839e825f8dcc91352837653e365a8f'
silent! let g:plugs['nvim-web-devicons'].commit = 'bdd43421437f2ef037e0dafeaaaa62b31d35ef2f'
silent! let g:plugs['playground'].commit = '71b00a3c665298e5155ad64a9020135808d4e3e8'
silent! let g:plugs['plenary.nvim'].commit = '25b3475b97f241e6f76249747bc209e70c5d2ec8'
silent! let g:plugs['popup.nvim'].commit = 'b7404d35d5d3548a82149238289fa71f7f6de4ac'
silent! let g:plugs['syntastic'].commit = 'b7f4f71539038d33f173bfa72631737da049575a'
silent! let g:plugs['tabular'].commit = '339091ac4dd1f17e225fe7d57b48aff55f99b23a'
silent! let g:plugs['targets.vim'].commit = '8d6ff2984cdfaebe5b7a6eee8f226a6dd1226f2d'
silent! let g:plugs['telescope-fzy-native.nvim'].commit = '7b3d2528102f858036627a68821ccf5fc1d78ce4'
silent! let g:plugs['telescope.nvim'].commit = '39b12d84e86f5054e2ed98829b367598ae53ab41'
silent! let g:plugs['termopen.vim'].commit = '3194a991a18a9be2fd9fcf8c4c55fe990c04b2bd'
silent! let g:plugs['tokyonight.nvim'].commit = '8223c970677e4d88c9b6b6d81bda23daf11062bb'
silent! let g:plugs['trouble.nvim'].commit = 'da61737d860ddc12f78e638152834487eabf0ee5'
silent! let g:plugs['ultisnips'].commit = 'f5ccf0977c611ffd774ca180774959301baaffad'
silent! let g:plugs['undotree'].commit = '08e259be24d4476c1ee745dc735eefd44f90efdc'
silent! let g:plugs['vim-airline'].commit = 'c4655701431a9c79704c827fd88a4783ec946879'
silent! let g:plugs['vim-airline-themes'].commit = '97cf3e6e638f936187d5f6e9b5eb1bdf0a4df256'
silent! let g:plugs['vim-be-good'].commit = 'bc499a06c14c729b22a6cc7e730a9fbc44d4e737'
silent! let g:plugs['vim-commentary'].commit = '3654775824337f466109f00eaf6759760f65be34'
silent! let g:plugs['vim-devicons'].commit = 'a2258658661e42dd4cdba4958805dbad1fe29ef4'
silent! let g:plugs['vim-dispatch'].commit = '00e77d90452e3c710014b26dc61ea919bc895e92'
silent! let g:plugs['vim-flake8'].commit = 'a99054ef98e8fdaefa1315af4649138bcadbfdf7'
silent! let g:plugs['vim-floaterm'].commit = 'ab7876f86c05c1935eb23a193f4f276132902ac1'
silent! let g:plugs['vim-fugitive'].commit = 'f529acef74b4266d94f22414c60b4a8930c1e0f3'
silent! let g:plugs['vim-gitbranch'].commit = '1a8ba866f3eaf0194783b9f8573339d6ede8f1ed'
silent! let g:plugs['vim-indent-object'].commit = '5c5b24c959478929b54a9e831a8e2e651a465965'
silent! let g:plugs['vim-nerdtree-syntax-highlight'].commit = '5178ee4d7f4e7761187df30bb709f703d91df18a'
silent! let g:plugs['vim-polyglot'].commit = '38282d58387cff48ac203f6912c05e4c8686141b'
silent! let g:plugs['vim-pydocstring'].commit = 'f6e3c52bfaf4b4f76dab4d84e75b94199d5f3b9c'
silent! let g:plugs['vim-quicklink'].commit = '021167741588555501594e1fc31f130b16acefa0'
silent! let g:plugs['vim-repeat'].commit = '24afe922e6a05891756ecf331f39a1f6743d3d5a'
silent! let g:plugs['vim-signify'].commit = '69498f6d49f3eeac06870012416dd9bf867b84f3'
silent! let g:plugs['vim-sneak'].commit = '94c2de47ab301d476a2baec9ffda07367046bec9'
silent! let g:plugs['vim-snippets'].commit = '6f270bb2d26c38765ff2243e9337c65f8a96a28b'
silent! let g:plugs['vim-startify'].commit = '81e36c352a8deea54df5ec1e2f4348685569bed2'
silent! let g:plugs['vim-surround'].commit = 'bf3480dc9ae7bea34c78fbba4c65b4548b5b1fea'
silent! let g:plugs['vim-test'].commit = '2240d7a4b868cb594b7d83544e1b6db4df806e5e'
silent! let g:plugs['vim-tmux-runner'].commit = '54767911fd5e6e2d8e493847149e315ac2e6531a'
silent! let g:plugs['vim-ultest'].commit = '6978fd32e3ca2c1c5591884eea0d57a7ee43d212'
silent! let g:plugs['vim-visualstar'].commit = 'a18cd0e7a03311ac709595c1d261ed44b45c9098'
silent! let g:plugs['vimtex'].commit = 'dfaca59bbbf0079ab1b4f159337ae7f17d1b5289'
silent! let g:plugs['which-key.nvim'].commit = 'bd4411a2ed4dd8bb69c125e339d837028a6eea71'
PlugUpdate!