wmwpy
Python module for working with Where's My...? game files.
This is being used in Where's My Editor, a level editor for the Where's My...? series.
Table of contents
Installation
To install wmwpy, run
pip install wmwpy
or
python -m pip install wmwpy
You can also install it from the source, which may be needed because it is frequently being updated, although you need to make sure git is installed.
pip install wmwpy@git+https://github.com/wmw-modding/wmwpy
Usage
Get game folder
To get started, you need to have a Where's My Water? game folder, either an extracted apk, ipa, or on a rooted / jailbroken device (for editing the game files directly). The game must be extracted like this.
- root
- assets
- ...
The assets folder can be specified in wmwpy.
Loading the game
Start by loading the game inside wmwpy
import wmwpy
game = wmwpy.load('game/wmw')
You can specify the assets folder
game = wmwpy.load('game/wmw', assets = '/assets')
You can set assets = '.' if you have the gamepath (first parameter) set to the assets folder (such as on a rooted / jailbroken device).
Alternately, you can specify the platform.
game = wmwpy.load('game/wmw', platform = 'android')
This automatically sets the assets folder to what it is on the platform.
| Platform | assets folder |
|---|---|
| android | /assets |
| ios | /Content |
You can also specify the game, which sets things up for that game.
game = wmwpy.load('game/wmp', game = 'WMP')
Currently all the games are
| Game | Code |
|---|---|
| Where's My Water? | 'WMW' |
| Where's My Water? Free | 'WMWF' |
| Where's My Perry? | 'WMP' |
| Where's My Perry? Free | 'WMPF' |
| Where's My Mickey? | 'WMM' |
| Where's My Mickey? XL | 'WMMXL' |
| Where's My Mickey? Free | 'WMMF' |
| Where's My XiYangYang? | 'WMXYY' |
| Where's My Water? Featuring XiYangYang | 'WMWFXYY' |
| Where's My Water? 2 | 'WMW2' |
| Where's My Holiday? | 'WMH' |
| Where's My Valentine? | 'WMV' |
| Where's My Summer? | 'WMS' |
You can also specify the base assets path, the folder within the assets folder that contains all the assets. For example, Where's My Perry? has all the data within /assets/Perry.
game = wmwpy.load('game/wmp', baseassets = '/Perry')
Each game has the database in a different location, so you can specify it.
game = wmwpy.load('game/wmp', db = '/Perry/Data/perry.db')
Since Where's My Water? 2 uses a profile instead of a database for the save data, you can also specify that.
game = wmwpy.load('game/wmw2', profile = '/Water/Data/factory_profile.json')
You can also provide a function to be called during the loading, so you can keep track of the current progress, e.g. in a gui application with a progress bar.
game = wmwpy.load('game/wmw', load_hook = lambda progress, text, max : print(f'({progress}/{max}) {text}'))
The inputs for the function are
(
progress : int,
text : str,
max : int,
)
Once you're done editing all the files, you need to dump the all the assets.
game.dump()
This will save all the files in the game inside the assets folder. You can customize this if you want them saved in a different location.
game.dump(folder = 'path/to/output')
Main classes
Level
To load a level from within a game, use the .Level() method.
level = game.Level('first_dig')
The first input can be the name of a level inside the /Levels folder (first_dig), an absolute path to the level (/Levels/first_dig), or the path to an xml file (/Levels/first_dig.xml).
You can also specify the xml and image separately.
level = game.Level(xmlPath = '/Levels/first_dig.xml', imagePath = '/Levels/first_dig.png')
Some levels include objects that wmwpy fails to load, so you can use the ignore_errors parameter to ignore them.
level = game.Level('first_dig', ignore_errors = True)
You can also use the HD or TabHD textures for the objects.
level = game.Level('first_dig', HD = True, TabHD = True)
If both are specified, TabHD will get priority. If it can't load TabHD textures. See hierarchy.
- TabHD
- HD
- Low Quality
You can also provide a function to run while loading to see the current progress.
level = game.Level('first_dig', load_callback = lambda progress, text, max : print(f'({progress}/{max}) {text}'))
The inputs for the function are
(
progress : int,
text : str,
max : int,
)
The objects in the level are all accessible in a list
>> level.objects
[
<wmwpy.classes.object.Object object at 0x000001C7627FE850>,
...
]
See Object
The level properties are also accessible as a dictionary
>> level.properties
{'HeavyIntro': '1'}
WMW2 challenges are also accessible in a list
>> level.challenges
[<wmwpy.classes.level.Level.Challenge object at 0x000001C72176ADD0>]
Once you're finished editing the level, you can get the xml.
xml = level.export(filename = '/Levels/first_dig.xml',)
This returns the xml file as bytes, but also saves the file to the game filesystem.
Challenges
Each challenge has requirements in a dictionary
>> level.challenges[0].requirements
{
'WinWait': {
'seconds': ''
},
'Duck': {
'count': '2'
}
}
Object
To load an object within a game, use the .Object() method.
obj = game.Object('/Objects/broken_pipe.hs')
You can also use the HD or TabHD textures for the objects.
level = game.Level('first_dig', HD = True, TabHD = True)
If both are specified, TabHD will get priority. If it can't load TabHD textures. See hierarchy.
- TabHD
- HD
- Low Quality
An object has many properties
>> obj.properties
{
'Type' : 'spout',
'SpoutType' : 'DrainSpout',
'Goal' : '1',
'GoalPreset', : 'Swampy',
}
An object also has many Sprites
>> obj.sprites
[<wmwpy.classes.sprite.Sprite object>]
The object image is a PIL image.
>> obj.image
<PIL.Image.Image image mode=RGBA size=300x300>
The image scale can be set
obj.scale = 20
You can also save a GIF of the object animations
obj.saveGIF('broken_pipe.gif')
Once you're finished editing the object, you can get the xml.
xml = export('/Objects/broken_pipe.hs',)
This returns the xml file as bytes, but also saves the file to the game filesystem.
Building package
To build the package, install build
pip install build
Then run
py -m build
Building docs
To build the docs, make sure sphinx is installed
pip install -r doc-build/requirements.txt
You then need to run
sphinx-build -b html doc-build docs
Credits
- Thanks to @campbellsonic for the script to read waltex images. I could not have done it without them.
- Thanks to Mark Setchell for helping to make loading waltex images faster (still need rgb565 and rgba5551).
Metadata
Release files for wmwpy 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wmwpy-1.0.0.tar.gz | 101.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wmwpy-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 205.4 kB
Release files / wmwpy-1.0.0.tar.gz
| Download URL | wmwpy-1.0.0.tar.gz |
|---|---|
| Size | 101.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1f81458735589c70243a8d1542ec659ee43858adccee9795ff98bf4b3ff4d042
|
|
BLAKE2b-256 checksum How to use checksums |
755f10f09a58492f337298a54c3aa47c5c5fb71d25f86026652ff8f8d8a825a6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 8, 2026.
Transparency logRelease files / wmwpy-1.0.0-py3-none-any.whl
| Download URL | wmwpy-1.0.0-py3-none-any.whl |
|---|---|
| Size | 103.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2c8edf6a4cabfdc542d982a3f406611a86d22097b10a478c0fde1bbe6b89f769
|
|
BLAKE2b-256 checksum How to use checksums |
cc136c30e4d10e9022a2309b8bfe3834a147ec07eea77cb1b56f46b4ec5da7ee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 8, 2026.
Transparency log