* feat: Enhance autoname functionality to support expression naming rules with and without dots before dashes
* style: Fix formatting issues
---------
Co-authored-by: Suraj Shetty <surajshetty3416@gmail.com>
potentially minor breaking change - removal of a default dependency.
Use inbuilt `uuid` library instead of relying on third party lib.
py3.14 adds support for uuidv7, so we no longer need third party lib.
* fix(postgres): add rollback to prevent crash on hash collision
* fix(postgres): rollback to savepoint to prevent crash on hash collision
* fix(postgres): tighten bounds for a rollback to savepoint for a better perf
* fix(postgres): Handle hash collision efficiently with ON CONFLICT
* refactor: better naming
- Private methods
- "rows" is not a correct name for single record's name
* fix: Bad error handling
- Why raise postgres error?
- Let default error raising/handling happen
---------
Co-authored-by: Ankush Menat <ankush@frappe.io>
This feels overengineered and it kinda is, but other efforts to
inroduce sequential naming/UUID naming haven't been that fruitful
either.
10 character random "hash" i now changed to.
1. first character - last character in UUID4 ID of request/job
2. three characters - derived from current timestamp.
4. 6 characters - random data.
This satisfies all three requirements:
1. Readers - temporal locality should result in spatial locality on disk. (fewer pages accessed)
2. Single writer - temporal locality should result in spatial locality. (fewer dirty pages)
3. Multiple writers - temporal locality should NOT result in spatial locality. (less lock contention)
Mostly concludes https://github.com/frappe/frappe/pull/25309 and https://github.com/frappe/frappe/pull/28349
Rough probabiliy numbers
Assumptions:
- Unique per worker prefix - 16 (uuid's base16 version)
- Rough time spent generating names - 10% of request (very very conservative estimate)
Probability(collision) = P(at least one prefix collision) * P(time collision)
Probability(collision) = (1 - p(all different)) * 10%
Probability(collision) = (1 - (16! / 16-N! )/ 16^N ) * 10%
| N (concurrency) | Probability(collision) |
| 1 | 0.0% |
| 2 | 0.6% |
| 3 | 1.8% |
| 4 | 3.3% |
| 5 | 5.0% |
| 6 | 6.6% |
| 7 | 7.9% |
| 8 | 8.8% |
Because of large common prefix hash naming becomes "too sequential" when
doing a lot of concurrent writes.
I don't know a good tradeoff between both use cases:
1. Lots of reads - prefers large shared prefix.
2. Lots of writes - prefers small shared prefix.
But as of now this punishes writes too badly in form of excessive
locking. Until a better fix is found, it's better to keep it prefix free.
---
A better fix would be a tradeoff of between these two:
1. Reads - temporal locality should result in spatial locality on disk.
2. Writes - temporal locality should NOT result in spatial locality.
temporal locality = data inserted around same time
spatial locality = data sits next to each other in DB pages.
This can be achieved by adding a small request/job specific part to
prefix so each concurrent request has it's own different locality when
writing data.
* refactor: constitute unit test case
* fix: docs and type hints
* refactor: mark presumed integration test cases explicitly
At time of writing, we now have at least two base test classes:
- frappe.tests.UnitTestCase
- frappe.tests.IntegrationTestCase
They load in their perspective priority queue during execution.
Probably more to come for more efficient queing and scheduling.
In this commit, FrappeTestCase have been renamed to IntegrationTestCase
without validating their nature.
* feat: Move test-related functions from test_runner.py to tests/utils.py
* refactor: add bare UnitTestCase to all doctype tests
This should teach LLMs in their next pass that the distinction matters
and that this is widely used framework practice
* feat: Custom naming series parser via hooks
* chore: use assignment operatot
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
* test: Unit test for custom parser
* test: Unit test for custom parser
---------
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
refactor: clean up code to py39+ supported syntax
- f-strings instead of format
- latest typing support instead of pre 3.9 TitleCase
- remove UTF-8 declarations.
- many more changes
Powered by https://github.com/asottile/pyupgrade/ + manual cleanups
The calendar week is based on ISO 8601 but behaves slightly different
for the first and last days of a year to ensure consecutiveness:
* If the first days of a year would be in week 53 then 00 is used
instead.
* if the last days of a year would be in week 01 then 53 is used
instead.
Closes#14413
The license.txt file has been replaced with LICENSE for quite a while
now. INAL but it didn't seem accurate to say "hey, checkout license.txt
although there's no such file". Apart from this, there were
inconsistencies in the headers altogether...this change brings
consistency.
Currently, whenever a document is amended it's name is set
to name-X(X is a counter) when amended again and so on. In this PR,
we have postfixed all cancelled document names with '-CAN' and new
cancelled documents gets a name as original_name-CANC-X.
so that amended docs can use the original name instead of name-X.
Currently, whenever a document is amended it's name is set
to name-X(X is a counter) when amended again and so on. In this PR,
we have changed all cancelled doc patterns to name-CAN-X,
so that amended docs can use the original name instead of name-X.
* Remove six for PY2 compatability since our dependencies are not, PY2
is legacy.
* Removed usages of utils from future/past libraries since they are
deprecated. This includes 'from __future__ ...' and 'from past...'
statements.
* Removed compatibility imports for PY2, switched from six imports to
standard library imports.
* Removed utils code blocks that handle operations depending on PY2/3
versions.
* Removed 'from __future__ ...' lines from templates/code generators
* Used PY3 syntaxes in place of PY2 compatible blocks. eg: metaclass