Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
98d48f7
Add flatdict as requirement
wengole Sep 25, 2018
bb4cc8d
Add wrapper to use flatdict to parse params as dict to kwargs
wengole Sep 25, 2018
13622b4
Add test for new wrapper
wengole Sep 25, 2018
2293888
Merge pull request #1 from nhsuk/dict-to-kwargs-wrapper
mikemonteith Sep 26, 2018
9864986
Make sure wrapper gets "installed"
wengole Sep 26, 2018
f613ca8
Merge pull request #2 from nhsuk/dict-to-kwargs-wrapper
mikemonteith Sep 26, 2018
e87373c
Added StreamBlockFactory and StreamBlockSubFactory
mikemonteith Sep 27, 2018
b7262d6
Merge pull request #3 from nhsuk/StreamBlockFactory
wengole Sep 27, 2018
ae7493a
Remove debug code
mikemonteith Oct 1, 2018
596914c
Assume value as default stream block key
mikemonteith Oct 1, 2018
4693915
Merge pull request #5 from nhsuk/streamfield-blocks
wengole Oct 3, 2018
9bef568
Fix changes to upstream factoryboy
wengole May 16, 2019
08d0605
Merge pull request #7 from nhsuk/remove-extract-dict
May 16, 2019
deb4d75
upgrade for wagtail 5, drop support for old versions
Jun 19, 2023
1cc3381
Merge pull request #9 from nhsuk/wagtail-5-support
bradmorton1 Jun 19, 2023
acdf432
update django version
prembonsall Jul 10, 2023
6915d40
Update tox.ini
prembonsall Jul 11, 2023
a2c47ed
Attempting to run unit tests with package versions unmodified
tomhosker-bjss Oct 23, 2025
1a36e99
Fix modeladmin
tomhosker-bjss Oct 24, 2025
e311fb0
Make unit tests run
tomhosker-bjss Oct 24, 2025
6e0389e
Make test_list_block_factory() pass
tomhosker-bjss Oct 24, 2025
0891594
Make test_list_block_factory() pass
tomhosker-bjss Oct 24, 2025
69b0cb7
Fix test_block_factory()
tomhosker-bjss Oct 27, 2025
7692b22
Fix test_block_factory_subkwarg()
tomhosker-bjss Oct 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,27 @@ Documentation is still in progress, but see the `tests`_ for more examples.
body__0__carousel__items__1__image__image__title='Image Slide 2',
body__0__carousel__items__2__label='Slide 3',
body__0__carousel__items__2__image__image__title='Image Slide 3')

Contributing
============

1. Clone the repo `git clone https://github.com/nhsuk/wagtail-streamfield-index.git`
2. Install dependencies `pip install .[testing,linting]`

If you are having issues in installing, it may be of use to use an environment tool
like [virtualenv](https://docs.python.org/3/library/venv.html)

Formatting
============

`black .`

Linting
============

`flake8 .`

Tests
============

`pytest`
71 changes: 37 additions & 34 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,65 @@
from setuptools import find_packages, setup

install_requires = [
'factory-boy>=2.8.0',
'wagtail>=1.12',
"factory-boy>=2.8.0",
"wagtail>=7.0.0",
"flatdict>=3.0.1",
"Django>=5.2.7",
"wagtail-modeladmin>=2.2.0"
]

docs_require = [
'sphinx>=1.4.0',
"sphinx>=1.4.0",
]

tests_require = [
'pytest==3.0.6',
'pytest-django==3.1.2',
'pytest-cov==2.4.0',
'pytest-pythonpath==0.7.1',
'psycopg2>=2.3.1',
'coverage==4.3.4',
"pytest==6.2.2",
"pytest-django==4.1.0",
"pytest-cov==2.4.0",
"pytest-pythonpath==0.7.1",
"psycopg2>=2.3.1",
"coverage==4.3.4",

'isort==4.2.5',
'flake8==3.3.0',
'flake8-blind-except==0.1.1',
'flake8-debugger==1.4.0',
"isort==4.2.5",
"flake8==3.3.0",
"flake8-blind-except==0.1.1",
"flake8-debugger==1.4.0",
]

with open('README.rst') as fh:
with open("README.rst") as fh:
long_description = re.sub(
'^.. start-no-pypi.*^.. end-no-pypi', '', fh.read(), flags=re.M | re.S)
"^.. start-no-pypi.*^.. end-no-pypi", "", fh.read(), flags=re.M | re.S)

setup(
name='wagtail_factories',
version='1.0.0',
description='Factory boy classes for wagtail',
name="wagtail_factories",
version="1.0.1",
description="Factory boy classes for wagtail",
long_description=long_description,
author="Michael van Tellingen",
author_email="[email protected]",
url='https://github.com/mvantellingen/wagtail-factories/',
url="https://github.com/mvantellingen/wagtail-factories/",
install_requires=install_requires,
tests_require=tests_require,
extras_require={
'docs': docs_require,
'test': tests_require,
"docs": docs_require,
"test": tests_require,
},
entry_points={},
package_dir={'': 'src'},
packages=find_packages('src'),
package_dir={"": "src"},
packages=find_packages("src"),
include_package_data=True,
license='MIT',
license="MIT",
classifiers=[
'Development Status :: 5 - Production/Stable',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
],
zip_safe=False,
)
3 changes: 2 additions & 1 deletion src/wagtail_factories/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .blocks import * # noqa
from .factories import * # noqa
from .wrapper import * # noqa

__version__ = '1.0.0'
__version__ = '1.0.1'
108 changes: 86 additions & 22 deletions src/wagtail_factories/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
import factory
from factory.declarations import ParameteredAttribute

try:
from wagtail.wagtailcore import blocks
from wagtail.wagtailimages.blocks import ImageChooserBlock
except ImportError:
from wagtail.core import blocks
from wagtail.images.blocks import ImageChooserBlock
from wagtail import blocks
from wagtail.images.blocks import ImageChooserBlock

from wagtail_factories.factories import ImageFactory
from wagtail_factories.builders import ListBlockStepBuilder

__all__ = [
'CharBlockFactory',
Expand All @@ -19,13 +16,17 @@
'ListBlockFactory',
'StructBlockFactory',
'ImageChooserBlockFactory',
'StreamBlockFactory',
'StreamBlockSubFactory',
]


class StreamFieldFactory(ParameteredAttribute):
"""
Syntax:
<streamfield>__<index>__<block_name>__<key>='foo',
or
<streamfield>__<index>__<block_name>='foo',

"""
def __init__(self, factories, **kwargs):
Expand All @@ -37,14 +38,20 @@ def generate(self, step, params):
result = defaultdict(lambda: defaultdict(lambda: defaultdict()))

for key, value in params.items():
try:
index, block_name, param = key.split('__', 2)
except ValueError:
continue
if not index.isdigit():
parts = key.split('__', 2)
index = parts[0]
if index.isdigit():
index = int(index)
else:
continue

index = int(index)
block_name = parts[1]

if len(parts) == 2:
param = 'value'
if len(parts) == 3:
param = parts[2]

result[index][block_name][param] = value

retval = []
Expand All @@ -62,28 +69,85 @@ def generate(self, step, params):


class ListBlockFactory(factory.SubFactory):
_builder_class = ListBlockStepBuilder

def __call__(self, **kwargs):
return self.evaluate(None, None, kwargs)

def evaluate(self, instance, step, extra):
result = defaultdict(dict)
for key, value in extra.items():
if key.isdigit():
result[int(key)]["value"] = value
else:
prefix, label = key.split("__", maxsplit=1)
if prefix and prefix.isdigit():
result[int(prefix)][label] = value

subfactory = self.get_factory()
force_sequence = step.sequence if self.FORCE_SEQUENCE else None
values = [
step.recurse(subfactory, params, force_sequence=force_sequence)
for _, params in sorted(result.items())
]

list_block_def = blocks.list_block.ListBlock(subfactory._meta.model())
return blocks.list_block.ListValue(list_block_def, values)


class StreamBlockSubFactory(factory.SubFactory):

def __call__(self, **kwargs):
return self.generate(None, kwargs)

def generate(self, step, params):
result = defaultdict(lambda: defaultdict(lambda: defaultdict()))
subfactory = self.get_factory()

result = defaultdict(dict)
for key, value in params.items():
if key.isdigit():
result[int(key)]['value'] = value
parts = key.split('__', 2)
index = parts[0]
if index.isdigit():
index = int(index)
else:
prefix, label = key.split('__', 2)
if prefix and prefix.isdigit():
result[int(prefix)][label] = value
continue

block_name = parts[1]

if len(parts) == 2:
result[index][block_name][block_name] = value
if len(parts) == 3:
param = parts[2]
result[index][block_name][block_name + "__" + param] = value

retval = []
for index, index_params in sorted(result.items()):
item = subfactory(**index_params)
retval.append(item)
return retval
for index, block_items in sorted(result.items()):
for block_name, block_params in block_items.items():
block_params['_block_name'] = block_name
step_builder = factory.builder.StepBuilder(
subfactory._meta,
block_params,
"build"
)
built = step_builder.build()
retval.append((block_name, built))

return blocks.StreamValue(subfactory._meta.model(), retval)


class StreamBlockFactory(factory.Factory):

@classmethod
def _build(cls, model_class, *args, **kwargs):
block = model_class()
block_name = kwargs['_block_name']
block_params = kwargs.get(block_name, None)
return block.to_python([{"type": block_name, "value": block_params}])[0].value

@classmethod
def _create(cls, model_class, *args, **kwargs):
return cls._build(model_class, *args, **kwargs)

class BlockFactory(factory.Factory):
class Meta:
abstract = True
Expand Down
Loading