Pre-commit flake8 with setup.cfg in subfolder - pre-commit-hook

I use flake8 with a bunch of plugins (flake8-docstrings, flake8-isort, flake8-black). I have them all pre-installed into a venv.
My repo to be checked with pre-commit:
Root folder has two packages
Each has its own
pyproject.toml (configures black and isort)
setup.cfg (configures flake8 and pydocstyle)
├── foo
│   ├── pyproject.toml
│   ├── setup.cfg
│   └── (the package)
├── bar
│   ├── pyproject.toml
│   ├── setup.cfg
│   └── (the package)
└── venv
I want to invoke flake8 via pre-commit for the two packages.
Here's how I do it currently:
---
repos:
- repo: local
hooks:
- id: flake8-foo
name: Run flake8 in foo package
entry: bash -c "cd foo && flake8"
language: python
- id: flake8-bar
name: Run flake8 in bar package
entry: bash -c "cd bar && flake8"
language: python
When I run pre-commit run --all-files and there's an error in foo, it prints the same output many times:
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
./path/in/foo/to/file.py:49:1: D401 First line should be in imperative mood
Is there a better way to go about this?
No, I am not open to splitting up the packages into their own repos
How can I have the error message only print once?

pre-commit by design operates on files, it also is optimized to batch runs of linters against files into multiple processes
what's happening here is your configuration is running several invocations (~1 per processor) of bash -c "cd bar && flake8" file1 file2 file3 etc. etc.
fortunately there's a setting you can use to fix this for you:
pass_filenames: false
with that:
---
repos:
- repo: local
hooks:
- id: flake8-foo
name: Run flake8 in foo package
entry: bash -c "cd foo && flake8"
language: python
pass_filenames: false
files: ^foo/
types: [python]
- id: flake8-bar
name: Run flake8 in bar package
entry: bash -c "cd bar && flake8"
language: python
pass_filenames: false
files: ^bar/
types: [python]
that said, you're losing most of the benefits of the framework by going to a repo: local hook:
pre-commit isn't managing the installation of the tools (each of your developers has to install the tool separately and at a particular version)
any filename-based optimizations aren't happening
if you only change one file, you're currently linting your whole repository twice
during merge conflicts, pre-commit optimizes which files to run (not the whole repo)
and more
what I'd suggest instead for your monorepo setup is to still call flake8 in the normal way but utilize --config such that it works against your sub-repos:
repos:
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.4
hooks:
- id: flake8
name: flake8 ./foo/
alias: flake8-foo
files: ^foo/
args: [--config, foo/setup.cfg]
- id: flake8
name: flake8 ./bar/
alias: flake8-bar
files: ^bar/
args: [--config, bar/setup.cfg]
disclaimer: I'm the author of pre-commit and the current maintainer of flake8

Related

How can I have GHCi reload include changes in the local dependent library?

Full reproducible project here: https://github.com/chrissound/215
I have the following simple cabal file which defines:
a library (source under src-lib)
executable (source under src) in the same project (which depends on the above local library)
cabal-version: 1.12
name: HaskellNixCabalStarter
version: 0.1.0.0
author: HaskellNixCabalStarter
maintainer: HaskellNixCabalStarter
license: MIT
build-type: Simple
library
exposed-modules:
Hello
other-modules:
Paths_HaskellNixCabalStarter
hs-source-dirs:
src-lib
build-depends:
base >=4.12 && <4.13
default-language: Haskell2010
executable app
main-is: Main.hs
other-modules:
Paths_HaskellNixCabalStarter
hs-source-dirs:
src
build-depends:
HaskellNixCabalStarter
, base >=4.12 && <4.13
default-language: Haskell2010
I can open a GHCi repl with:
cabal v2-repl app
However, upon GHCi reloading (:r), it will only reload changes in the app executable, and disregard any changes in the library.
This seems like very limiting / incorrect behavior. How can I fix this / workaround this?
There is a workaround, you either
run cabal repl and then :load src/Main.hs, or
with cabal repl app you'd need to :load src/Main.hs src-lib/Hello.hs.
Now :reload also reloads changes from dependencies.
In the first case it's the :load that somehow also starts loading/following the dependencies. (Not sure why cabal repl app isn't doing exactly the same.)
On the second case you need to explicitly name the modules you want to follow. Also, you need to have the module in who's namespace you want to be in, first. So :load src/Main.hs ..others...
See this on reddit. It appears that cabal can only have one "unit" loaded, but loading other sources with :load seems to subvert that.
I don't think it can be done (yet?). Evidence:
jeff#jbb-dell:cabal-experim$ tree
.
├── cabal.project
├── P1
│   ├── app
│   │   ├── Lib.hs
│   │   └── Main.hs
│   └── P1.cabal
└── P2
├── P2.cabal
└── src
└── MyLib.hs
jeff#jbb-dell:cabal-experim$ cabal repl P1 P2
cabal: Cannot open a repl for multiple components at once. The targets 'P1'
and 'P2' refer to different components.
The reason for this limitation is that current versions of ghci do not support
loading multiple components as source. Load just one component and when you
make changes to a dependent component then quit and reload.

Importing a haskell module from the parent directory

Given the following directory structure:
root
├── scripts
│   └── script1.hs
└── source
   ├── librarymodule.hs
   └── libraryconfig.txt
Where "librarymodule.hs" would be a library exporting multiple functions, where the output is influenced by the contents of the libraryconfig.txt file in his directory.
script1.hs is the file needing to use the functions declared in librarymodule.hs.
I can't find a solution on the internet for a structure as given above and hoped someone could help out.
GHC has a -i option. Under root/scripts/, this will add root/source/ to the search path:
ghc -i../source script1.hs
Also consider packaging your library using cabal so you can install it and use it anywhere without worrying about paths.
Here is a minimal example of a library with data-files:
source/
├── mylibrary.cabal
├── LibraryModule.hs
└── libraryconfig.txt
mylibrary.cabal
name: mylibrary
version: 0.0.1
build-type: Simple
cabal-version: >= 1.10
data-files: libraryconfig.txt
library
exposed-modules: LibraryModule
other-modules: Paths_mylibrary
build-depends: base
default-language: Haskell2010
LibraryModule.hs
module LibraryModule where
import Paths_mylibrary -- This module will be generated by cabal
-- Some function that uses the data-file
printConfig :: IO ()
printConfig = do
n <- getDataFileName "libraryconfig.txt"
-- Paths_mylibrary.getDataFileName resolves paths for files associated with mylibrary
c <- readFile n
print c
See this link for information about the Paths_* module: https://www.haskell.org/cabal/users-guide/developing-packages.html#accessing-data-files-from-package-code
Now running cabal install should install mylibrary.
Then, under scripts/script1.hs, you can just run ghc script1.hs, using the library you installed.

Stack using binaries of other package

I have two projects in my user directory ~, the project A and B.
I run stack init and later stack build on the project A. Then, I have
the binaries of the A package in a folder ~/.stack-work/install/x86_64-linux/lts-6.0/7.10.3/bin. The issue is B needs this version of the binaries from A package, and then try the same build with stack on the B project directory. I tried on ~/B run the following command without success.
stack build ~/.stack-work/install/x86_64-linux/lts-6.0/7.10.3/bin
How can I do that? What if I create a third package C, and need something similar?
Excerpts:
The A.cabal content.
name: A
version: 1.1
And the B.cabal.
name: B
version: 1.0
build-depends: A>= 1.1
Then,
$ stack init
Looking for .cabal or package.yaml files to use to init the project.
Using cabal packages:
- B.cabal
Selecting the best among 8 snapshots...
* Partially matches lts-6.0
A version 1.0 found
- A requires ==1.1
This may be resolved by:
- Using '--omit-packages to exclude mismatching package(s).
- Using '--resolver' to specify a matching snapshot/resolver
But I actually have the version 1.1 of A build.
You don't need to include the project A's bin directory - that was a red herring.
Organize your files like this:
.
├── stack.yaml
├── project-A
│   ├── LICENSE.txt
│   ├── Setup.hs
│   ├── project-A.cabal
│   └── src
│   └── ...
│
└── project-B
   ├── Setup.hs
   ├── project-B.cabal
   └── src
   └── ...
Your top-level stack.yaml file will look like:
resolver: lts-5.13
packages:
- project-A/
- project-B/
Then in the top-level directory run stack build.
I'll take a stab at answering your question...
How about putting
~/.stack-work/install/x86_64-linux/lts-6.0/7.10.3/bin
in your PATH? If the other project really needs binaries (i.e. programs) built by another project, this would be the way to do it.
Or, copy the built programs to some directory in your current PATH - i.e. /usr/local/bin or ~/bin.
If this doesn't answer your question, please post the cabal files for both projects.
I found an answer after digging into the FAQ of stack. Create a file stack.yaml into B folder. At first the content could be:
resolver: lts-6.0
packages:
- '.'
- '/home/jonaprieto/A'
extra-deps: []
Then, it runs:
$ stack build

Using HSpec with Stack

I have the following architecture :
backend
├── Chat.hs
├── Main.hs
└── Message.hs
test
├── backendSpec
│ └── MessageSpec.hs
└── Spec.hs
My .cabal file contains the following
test-suite spec
build-depends: base, hspec == 2.*,
snap >= 0.14.0.6,
containers,
aeson,
text,
transformers,
stm,
snap-core,
snap-server,
socket-io,
engine-io-snap,
snap-cors,
bytestring
hs-source-dirs: test
main-is: Spec.hs
Type: exitcode-stdio-1.0
but when I do
stack test
HSpec cannot find my test int MessageSpec.hs.
Finished in 0.0002 seconds
0 examples, 0 failures
Spec.hs is the correct input : {-# OPTIONS_GHC -F -pgmF hspec-discover #-}
and my MessageSpec module is exposing : module MessageSpec (main, spec).
Could you help me find a way to make my stack project doing all my tests.
Thank you,
Your path to your spec must follow the module name convention. backendSpec.MessageSpec is not a valid module name, since it starts with a lowercase letter.
Furthermore, the module name of your spec should only differ by the additional suffix Spec from your original module. Your modules in backendSpec wouldn't follow this:
module Message where ...
-- vs
module BackendSpec.MessageSpec where ...
So to fix this, make sure that all directories in your test directory start with an uppercase letter. But even better, make sure that the test directory has the same structure as your src directory, as this will result in better module names during your tests:
-- If file is test/BackendSpec/MessageSpec.hs
BackendSpec.Message:
<someDescription>
<some assertion>
<some assertion>
<some assertion>
vs
-- If file is test/MessageSpec.hs
Message:
<someDescription>
<some assertion>
<some assertion>
<some assertion>
(The relevant code for this behaviour can be found in hspec/Run.hs of hspec-discover)

Debian Package Creation- How to install configuration files?

I've been really stuck on this minor (I'm sure) issue so any help would be greatly appreciated. I've created a standard ubuntu package with dh_make. The purpose of this package is to create a package that will set up all the ldap related packages that a system needs including it's configuration. One of the steps I'm trying to do is to copy over an /etc/ldap.conf file while making a backup of the existing file. How do I do this? I tried to create a postinst script that looks essentially like the following, but I'm not clear on how the package stores the files and I get an error saying missing etc/ldap.conf file. What's the best way to do this? Here is my postinst script:
#!/bin/bash -xv
install -v -b etc/ldap.conf /etc/ldap.conf > /tmp/tst 2>&1
Here is my skeleton structure:
root#hqd-clientb-16:~/navldapubuntu-0.1/debian# tree
├── changelog
├── compat
├── control
├── copyright
├── docs
├── etc
   └── ldap.conf
├── install
├── postinst
├── README.Debian
├── README.source
├── rules
├── source
   └── format
├── navldapubuntu
   └── etc
├── navldapubuntu.debhelper.log
├── navldapubuntu.dirs
└── navldapubuntu.doc-base.EX
Here's some additional information of the package I created.
dpkg --contents tnoldapubuntu_0.1-1_all.deb (truncated output)
./usr/
./usr/share/
./usr/share/doc
./usr/share/doc/navldapubuntu/
./usr/share/doc/navldapubuntu/copyright
./usr/share/doc/navldapubuntu/README.Debian
./usr/share/doc/navldapubuntu/changelog.Debian.gz
./etc/ldap.conf
There is a special tool that designed for creation of configuration packages: http://debathena.mit.edu/config-packages
Here is a simple template that could be helpful for a quick start.
List of files
template (directory)
template/debian (directory)
template/debian/control
template/debian/changelog
template/debian/displace
template/debian/rules
template/debian/postinst
template/debian/install
template/debian/docs
template/debian/compat
template/README
template/BUILD
template/files (directory)
template/files/etc/ldap.conf.mycompanyname
Content
template/debian/control:
Source: PACKAGE_NAME
Section: morpho/misc
Priority: optional
Maintainer: MAINTAINER
Build-Depends: debhelper, config-package-dev (>= 5.0~)
Package: PACKAGE_NAME
Architecture: all
Depends: ${misc:Depends}, DEPENDENCY [, DEPENDENCY ...]
Provides: ${diverted-files}
Conflicts: ${diverted-files}
Description: PACKAGE_DESCRIPTION_SHORT
PACKAGE_DESCRIPTION_LONG.
template/debian/displace
/etc/ldap/ldap.conf.mycompanyname
template/debian/install
files/* /
template/debian/postinst
#!/bin/sh
set -e
#DEBHELPER#
POSTINST_SCRIPT
template/debian/rules
#!/usr/bin/make -f
# Exclude *.svn* from building
# you probably don't need this if don't use SVN
export DH_ALWAYS_EXCLUDE=.svn
# Core (check http://debathena.mit.edu/config-packages for more information)
%:
dh $# --with=config-package
# Prevent dh_installdeb of treating files in /etc as configuration files
# you need this if need configuration files been always rewritten
# even if changed
override_dh_installdeb:
dh_installdeb
rm debian/*/DEBIAN/conffiles
template/debian/docs
README
BUILD
And finally you can build this package with the following command:
dpkg-buildpackage -us -uc -I.svn
You need to create a "conffiles" file in the DEBIAN directory, next to the "control" file, and declare /etc/ldap.conf in it. So this file will be automatically considered a configuration file, and changes to it will prompt a "new config file, would you want to overwrite, yadda yadda".

Resources