mirror of
https://github.com/simonmichael/hledger.git
synced 2024-11-13 06:05:17 +03:00
imp: run checks in a well-defined order; and tweak that order
Now commodities are checked before accounts, and tags before recentassertions. Also some check doc cleanups.
This commit is contained in:
parent
4cbf72ab1f
commit
55401282a0
@ -8,6 +8,7 @@ others can be called only via the check command.
|
|||||||
{-# LANGUAGE NamedFieldPuns #-}
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
|
||||||
module Hledger.Data.JournalChecks (
|
module Hledger.Data.JournalChecks (
|
||||||
|
journalStrictChecks,
|
||||||
journalCheckAccounts,
|
journalCheckAccounts,
|
||||||
journalCheckBalanceAssertions,
|
journalCheckBalanceAssertions,
|
||||||
journalCheckCommodities,
|
journalCheckCommodities,
|
||||||
@ -42,6 +43,15 @@ import Data.Ord
|
|||||||
import Hledger.Data.Dates (showDate)
|
import Hledger.Data.Dates (showDate)
|
||||||
import Hledger.Data.Balancing (journalBalanceTransactions, defbalancingopts)
|
import Hledger.Data.Balancing (journalBalanceTransactions, defbalancingopts)
|
||||||
|
|
||||||
|
-- | Run the extra -s/--strict checks on a journal, in order of priority,
|
||||||
|
-- returning the first error message if any of them fail.
|
||||||
|
journalStrictChecks :: Journal -> Either String ()
|
||||||
|
journalStrictChecks j = do
|
||||||
|
-- keep the order of checks here synced with Check.md and Hledger.Cli.Commands.Check.Check.
|
||||||
|
-- journalCheckOrdereddates j
|
||||||
|
-- journalCheckBalanceAssertions j
|
||||||
|
journalCheckCommodities j
|
||||||
|
journalCheckAccounts j
|
||||||
|
|
||||||
-- | Check that all the journal's postings are to accounts with
|
-- | Check that all the journal's postings are to accounts with
|
||||||
-- account directives, returning an error message otherwise.
|
-- account directives, returning an error message otherwise.
|
||||||
|
@ -107,7 +107,6 @@ module Hledger.Read (
|
|||||||
orDieTrying,
|
orDieTrying,
|
||||||
|
|
||||||
-- * Misc
|
-- * Misc
|
||||||
journalStrictChecks,
|
|
||||||
saveLatestDates,
|
saveLatestDates,
|
||||||
saveLatestDatesForFiles,
|
saveLatestDatesForFiles,
|
||||||
|
|
||||||
@ -159,7 +158,7 @@ import Hledger.Read.RulesReader (tests_RulesReader)
|
|||||||
-- import Hledger.Read.TimeclockReader (tests_TimeclockReader)
|
-- import Hledger.Read.TimeclockReader (tests_TimeclockReader)
|
||||||
import Hledger.Utils
|
import Hledger.Utils
|
||||||
import Prelude hiding (getContents, writeFile)
|
import Prelude hiding (getContents, writeFile)
|
||||||
import Hledger.Data.JournalChecks (journalCheckAccounts, journalCheckCommodities)
|
import Hledger.Data.JournalChecks (journalStrictChecks)
|
||||||
|
|
||||||
--- ** doctest setup
|
--- ** doctest setup
|
||||||
-- $setup
|
-- $setup
|
||||||
@ -307,13 +306,6 @@ readJournalFilesAndLatestDates iopts pfs = do
|
|||||||
(js, lastdates) <- unzip <$> mapM (readJournalFileAndLatestDates iopts) pfs
|
(js, lastdates) <- unzip <$> mapM (readJournalFileAndLatestDates iopts) pfs
|
||||||
return (maybe def sconcat $ nonEmpty js, catMaybes lastdates)
|
return (maybe def sconcat $ nonEmpty js, catMaybes lastdates)
|
||||||
|
|
||||||
-- | Run the extra -s/--strict checks on a journal,
|
|
||||||
-- returning the first error message if any of them fail.
|
|
||||||
journalStrictChecks :: Journal -> Either String ()
|
|
||||||
journalStrictChecks j = do
|
|
||||||
journalCheckAccounts j
|
|
||||||
journalCheckCommodities j
|
|
||||||
|
|
||||||
-- | An easy version of 'readJournal' which assumes default options, and fails
|
-- | An easy version of 'readJournal' which assumes default options, and fails
|
||||||
-- in the IO monad.
|
-- in the IO monad.
|
||||||
readJournal' :: Text -> IO Journal
|
readJournal' :: Text -> IO Journal
|
||||||
|
@ -11,7 +11,7 @@ module Hledger.Cli.Commands.Check (
|
|||||||
|
|
||||||
import Data.Char (toLower)
|
import Data.Char (toLower)
|
||||||
import Data.Either (partitionEithers)
|
import Data.Either (partitionEithers)
|
||||||
import Data.List (isPrefixOf, find)
|
import Data.List (isPrefixOf, find, sort)
|
||||||
import Control.Monad (forM_)
|
import Control.Monad (forM_)
|
||||||
import System.Console.CmdArgs.Explicit
|
import System.Console.CmdArgs.Explicit
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ check copts@CliOpts{rawopts_} j = do
|
|||||||
|
|
||||||
case partitionEithers (map parseCheckArgument args) of
|
case partitionEithers (map parseCheckArgument args) of
|
||||||
(unknowns@(_:_), _) -> error' $ "These checks are unknown: "++unwords unknowns
|
(unknowns@(_:_), _) -> error' $ "These checks are unknown: "++unwords unknowns
|
||||||
([], checks) -> forM_ checks $ runCheck copts' j
|
([], checks) -> forM_ (sort checks) $ runCheck copts' j
|
||||||
|
|
||||||
-- | Regenerate this CliOpts' report specification, after updating its
|
-- | Regenerate this CliOpts' report specification, after updating its
|
||||||
-- underlying report options with the given update function.
|
-- underlying report options with the given update function.
|
||||||
@ -49,26 +49,25 @@ cliOptsUpdateReportSpecWith roptsupdate copts@CliOpts{reportspec_} =
|
|||||||
Right rs -> copts{reportspec_=rs}
|
Right rs -> copts{reportspec_=rs}
|
||||||
|
|
||||||
-- | A type of error check that we can perform on the data.
|
-- | A type of error check that we can perform on the data.
|
||||||
-- Some of these imply other checks that are done first,
|
-- If performing multiple checks, they will be performed in the order defined here, generally.
|
||||||
-- eg currently Parseable and Autobalanced are always done,
|
-- (We report only the first failure, so the more useful checks should come first.)
|
||||||
-- and Assertions are always done unless -I is in effect.
|
|
||||||
data Check =
|
data Check =
|
||||||
|
-- keep the order here synced with Check.md and Hledger.Data.JournalChecks.journalStrictChecks.
|
||||||
-- done always
|
-- done always
|
||||||
Parseable
|
Parseable
|
||||||
| Autobalanced
|
| Autobalanced
|
||||||
-- done always unless -I is used
|
| Assertions -- unless -I is used
|
||||||
| Assertions
|
-- done when --strict is used, or when specified with the check command
|
||||||
-- done when -s is used, or on demand by check
|
|
||||||
| Accounts
|
|
||||||
| Commodities
|
|
||||||
| Balanced
|
| Balanced
|
||||||
-- done on demand by check
|
| Commodities
|
||||||
|
| Accounts
|
||||||
|
-- done when specified with the check command
|
||||||
| Ordereddates
|
| Ordereddates
|
||||||
| Payees
|
| Payees
|
||||||
| Recentassertions
|
|
||||||
| Tags
|
| Tags
|
||||||
|
| Recentassertions
|
||||||
| Uniqueleafnames
|
| Uniqueleafnames
|
||||||
deriving (Read,Show,Eq,Enum,Bounded)
|
deriving (Read,Show,Eq,Enum,Bounded,Ord)
|
||||||
|
|
||||||
-- | Parse the name (or a name prefix) of an error check, or return the name unparsed.
|
-- | Parse the name (or a name prefix) of an error check, or return the name unparsed.
|
||||||
-- Check names are conventionally all lower case, but this parses case insensitively.
|
-- Check names are conventionally all lower case, but this parses case insensitively.
|
||||||
@ -97,6 +96,12 @@ runCheck _opts j (chck,_) = do
|
|||||||
d <- getCurrentDay
|
d <- getCurrentDay
|
||||||
let
|
let
|
||||||
results = case chck of
|
results = case chck of
|
||||||
|
-- these checks are assumed to have passed earlier during journal parsing:
|
||||||
|
Parseable -> Right ()
|
||||||
|
Autobalanced -> Right ()
|
||||||
|
Balanced -> Right ()
|
||||||
|
Assertions -> Right ()
|
||||||
|
|
||||||
Accounts -> journalCheckAccounts j
|
Accounts -> journalCheckAccounts j
|
||||||
Commodities -> journalCheckCommodities j
|
Commodities -> journalCheckCommodities j
|
||||||
Ordereddates -> journalCheckOrdereddates j
|
Ordereddates -> journalCheckOrdereddates j
|
||||||
@ -104,8 +109,6 @@ runCheck _opts j (chck,_) = do
|
|||||||
Recentassertions -> journalCheckRecentAssertions d j
|
Recentassertions -> journalCheckRecentAssertions d j
|
||||||
Tags -> journalCheckTags j
|
Tags -> journalCheckTags j
|
||||||
Uniqueleafnames -> journalCheckUniqueleafnames j
|
Uniqueleafnames -> journalCheckUniqueleafnames j
|
||||||
-- the other checks have been done earlier during withJournalDo
|
|
||||||
_ -> Right ()
|
|
||||||
|
|
||||||
case results of
|
case results of
|
||||||
Right () -> return ()
|
Right () -> return ()
|
||||||
|
@ -4,7 +4,7 @@ Check for various kinds of errors in your data.
|
|||||||
|
|
||||||
_FLAGS
|
_FLAGS
|
||||||
|
|
||||||
hledger provides a number of built-in error checks to help
|
hledger provides a number of built-in correctness checks to help
|
||||||
prevent problems in your data.
|
prevent problems in your data.
|
||||||
Some of these are run automatically; or,
|
Some of these are run automatically; or,
|
||||||
you can use this `check` command to run them on demand,
|
you can use this `check` command to run them on demand,
|
||||||
@ -22,63 +22,64 @@ hledger check ordereddates payees # basic + two other checks
|
|||||||
If you are an Emacs user, you can also configure flycheck-hledger to run these checks,
|
If you are an Emacs user, you can also configure flycheck-hledger to run these checks,
|
||||||
providing instant feedback as you edit the journal.
|
providing instant feedback as you edit the journal.
|
||||||
|
|
||||||
Here are the checks currently available:
|
Here are the checks currently available.
|
||||||
|
They are performed in the order they are shown here.
|
||||||
|
(Eg, an `ordereddates` failure takes precedence over an `assertions` failure).
|
||||||
|
|
||||||
### Default checks
|
### Default checks
|
||||||
|
|
||||||
These checks are run automatically by (almost) all hledger commands:
|
These checks are always performed, by (almost) all hledger commands:
|
||||||
|
|
||||||
- **parseable** - data files are in a supported [format](hledger.md#data-formats),
|
- **parseable** - data files are in a supported [format](#data-formats),
|
||||||
with no syntax errors and no invalid include directives.
|
with no syntax errors and no invalid include directives
|
||||||
|
|
||||||
- **autobalanced** - all transactions are [balanced](hledger.html#postings), after converting to cost.
|
- **autobalanced** - all transactions are [balanced](#postings),
|
||||||
Missing amounts and missing [costs] are inferred automatically where possible.
|
after inferring missing amounts and conversion [costs] where possible,
|
||||||
|
and then converting to cost
|
||||||
|
|
||||||
- **assertions** - all [balance assertions] in the journal are passing.
|
- **assertions** - all [balance assertions] in the journal are passing.
|
||||||
(This check can be disabled with `-I`/`--ignore-assertions`.)
|
(This check can be disabled with `-I`/`--ignore-assertions`.)
|
||||||
|
|
||||||
### Strict checks
|
### Strict checks
|
||||||
|
|
||||||
These additional checks are run when the `-s`/`--strict` ([strict mode]) flag is used.
|
These additional checks are run when the `-s`/`--strict` ([strict mode])
|
||||||
Or, they can be run by giving their names as arguments to `check`:
|
flag is used with any command; or,
|
||||||
|
when they are given as arguments to the `check` command:
|
||||||
|
|
||||||
- **balanced** - all transactions are balanced after converting to cost,
|
- **balanced** - like `autobalanced`, but conversion costs will not be
|
||||||
without inferring missing costs.
|
inferred, and must be written explicitly
|
||||||
If conversion costs are required, they must be explicit.
|
|
||||||
|
|
||||||
- **accounts** - all account names used by transactions
|
|
||||||
[have been declared](hledger.html#account-error-checking)
|
|
||||||
|
|
||||||
- **commodities** - all commodity symbols used
|
- **commodities** - all commodity symbols used
|
||||||
[have been declared](hledger.html#commodity-error-checking)
|
[have been declared](#commodity-error-checking)
|
||||||
|
|
||||||
|
- **accounts** - all account names used
|
||||||
|
[have been declared](#account-error-checking)
|
||||||
|
|
||||||
### Other checks
|
### Other checks
|
||||||
|
|
||||||
These checks can be run only by giving their names as arguments to `check`.
|
These checks can be run by giving their names as arguments to `check`:
|
||||||
They are more specialised and not desirable for everyone:
|
|
||||||
|
|
||||||
- **ordereddates** - transactions are ordered by date within each file
|
- **ordereddates** - within each file, transactions are ordered by date
|
||||||
|
|
||||||
- **payees** - all payees used by transactions [have been declared](#payee-directive)
|
- **payees** - all payees used by transactions [have been declared](#payee-directive)
|
||||||
|
|
||||||
|
- **tags** - all tags used by transactions [have been declared](#tag-directive)
|
||||||
|
|
||||||
- **recentassertions** - all accounts with balance assertions have a
|
- **recentassertions** - all accounts with balance assertions have a
|
||||||
balance assertion within 7 days of their latest posting
|
balance assertion within 7 days of their latest posting
|
||||||
|
|
||||||
- **tags** - all tags used by transactions [have been declared](#tag-directive)
|
|
||||||
|
|
||||||
- **uniqueleafnames** - all account leaf names are unique
|
- **uniqueleafnames** - all account leaf names are unique
|
||||||
|
|
||||||
### Custom checks
|
### Custom checks
|
||||||
|
|
||||||
A few more checks are are available as separate [add-on commands],
|
You can build your own custom checks with [add-on command scripts].
|
||||||
in <https://github.com/simonmichael/hledger/tree/master/bin>:
|
(See also [Cookbook > Scripting](scripting.html).)
|
||||||
|
Here are some examples from [hledger/bin/](https://github.com/simonmichael/hledger/tree/master/bin):
|
||||||
|
|
||||||
- **hledger-check-tagfiles** - all tag values containing / (a forward slash) exist as file paths
|
- **hledger-check-tagfiles** - all tag values containing / (a forward slash) exist as file paths
|
||||||
|
|
||||||
- **hledger-check-fancyassertions** - more complex balance assertions are passing
|
- **hledger-check-fancyassertions** - more complex balance assertions are passing
|
||||||
|
|
||||||
You could make similar scripts to perform your own custom checks.
|
|
||||||
See: Cookbook -> [Scripting](scripting.html).
|
|
||||||
|
|
||||||
### More about specific checks
|
### More about specific checks
|
||||||
|
|
||||||
@ -92,7 +93,7 @@ It assumes that adding a balance assertion requires/reminds you to check the rea
|
|||||||
in that case, I recommend to import transactions uncleared,
|
in that case, I recommend to import transactions uncleared,
|
||||||
and when you manually review and clear them, also check the latest assertion against the real-world balance.)
|
and when you manually review and clear them, also check the latest assertion against the real-world balance.)
|
||||||
|
|
||||||
[add-on commands]: #add-on-commands
|
[add-on command scripts]: #add-on-commands
|
||||||
[balance assertions]: #balance-assertions
|
[balance assertions]: #balance-assertions
|
||||||
[strict mode]: #strict-mode
|
[strict mode]: #strict-mode
|
||||||
[costs]: #costs
|
[costs]: #costs
|
||||||
|
@ -16,10 +16,12 @@ $ hledger -f- check accounts
|
|||||||
|
|
||||||
# ** 3. also fails for forecast accounts
|
# ** 3. also fails for forecast accounts
|
||||||
<
|
<
|
||||||
|
commodity $
|
||||||
account a
|
account a
|
||||||
~ 2022-01-31
|
~ 2022-01-31
|
||||||
a $1
|
a $1
|
||||||
b
|
b
|
||||||
|
|
||||||
$ hledger -f- --today 2022-01-01 --forecast check accounts
|
$ hledger -f- --today 2022-01-01 --forecast check accounts
|
||||||
>2 /account "b" has not been declared/
|
>2 /account "b" has not been declared/
|
||||||
>=1
|
>=1
|
||||||
@ -31,6 +33,7 @@ $ hledger -f- --today 2022-01-01 --forecast --strict bal
|
|||||||
|
|
||||||
# ** 5. also fails for auto accounts
|
# ** 5. also fails for auto accounts
|
||||||
<
|
<
|
||||||
|
commodity $
|
||||||
account a
|
account a
|
||||||
|
|
||||||
= a
|
= a
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
# check ordereddates succeeds when transaction dates are ordered
|
# * check ordereddates
|
||||||
|
# ** 1. check ordereddates succeeds when transaction dates are ordered
|
||||||
<
|
<
|
||||||
2020-01-01
|
2020-01-01
|
||||||
2020-01-01
|
2020-01-01
|
||||||
2020-01-02
|
2020-01-02
|
||||||
$ hledger -f- check ordereddates
|
$ hledger -f- check ordereddates
|
||||||
|
|
||||||
# and otherwise fails
|
# ** 2. and otherwise fails
|
||||||
<
|
<
|
||||||
2020-01-01
|
2020-01-01
|
||||||
2020-01-02
|
2020-01-02
|
||||||
@ -15,18 +16,12 @@ $ hledger -f- check ordereddates
|
|||||||
>2 /date .*is out of order/
|
>2 /date .*is out of order/
|
||||||
>=1
|
>=1
|
||||||
|
|
||||||
# With --date2, it checks secondary dates instead
|
# ** 3. --date2 and secondary dates are ignored
|
||||||
<
|
<
|
||||||
2020-01-02
|
2020-01-02
|
||||||
2020-01-01=2020-01-03
|
2020-01-01=2020-01-03
|
||||||
$ hledger -f- check ordereddates --date2
|
$ hledger -f- check ordereddates --date2
|
||||||
|
>2 /date .*is out of order/
|
||||||
#
|
|
||||||
<
|
|
||||||
2020-01-01=2020-01-03
|
|
||||||
2020-01-02
|
|
||||||
$ hledger -f- check ordereddates --date2
|
|
||||||
>2 /date2 .*is out of order/
|
|
||||||
>=1
|
>=1
|
||||||
|
|
||||||
# XXX not supported: With a query, only matched transactions' dates are checked.
|
# XXX not supported: With a query, only matched transactions' dates are checked.
|
||||||
|
Loading…
Reference in New Issue
Block a user