{"id":1663,"library":"pyshp","title":"Pyshp: Pure Python ESRI Shapefile Reader/Writer","description":"Pyshp (The Python Shapefile Library) is a pure Python library designed for reading and writing ESRI Shapefile format files. It allows developers to work with geospatial vector data without external dependencies. The library is currently in version 3.0.3 and maintains an active development and release cadence.","status":"active","version":"3.0.3","language":"en","source_language":"en","source_url":"https://github.com/GeospatialPython/pyshp","tags":["gis","shapefile","geospatial","esri","vector-data","pure-python"],"install":[{"cmd":"pip install pyshp","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Requires Python 3.9 or newer.","package":"python","optional":false},{"reason":"Optional dependency for static type checking support.","package":"pyshp-stubs","optional":true}],"imports":[{"note":"The library is imported as 'shapefile', not 'pyshp'.","symbol":"Reader","correct":"import shapefile\nreader = shapefile.Reader('my_shapefile.shp')"},{"note":"The library is imported as 'shapefile', not 'pyshp'.","symbol":"Writer","correct":"import shapefile\nwriter = shapefile.Writer('new_shapefile.shp')"}],"quickstart":{"code":"import shapefile\nimport os\n\n# Create a dummy shapefile for reading example\noutput_dir = 'temp_shapefile_dir'\nos.makedirs(output_dir, exist_ok=True)\n\nw = shapefile.Writer(os.path.join(output_dir, 'test_points.shp'))\nw.field('name', 'C')\nw.point(1, 1)\nw.record('Point A')\nw.point(2, 2)\nw.record('Point B')\nw.close()\n\n# Reading a shapefile\n# You specify the base filename of the shapefile or any of its component files.\n# Using a context manager is recommended for automatic file closing.\nwith shapefile.Reader(os.path.join(output_dir, 'test_points.shp')) as sf:\n    print(f\"Shape type: {sf.shapeTypeName}\")\n    print(f\"Number of shapes: {len(sf.shapes())}\")\n    for shapeRec in sf.iterShapeRecords():\n        print(f\"Geometry: {shapeRec.shape.points}, Record: {shapeRec.record}\")\n\n# Writing a new shapefile\nwith shapefile.Writer(os.path.join(output_dir, 'new_polygon.shp')) as w:\n    w.shapeType = shapefile.POLYGON\n    w.field(\"Name\", \"C\")\n    w.field(\"Area\", \"N\")\n    \n    # Add a polygon\n    w.poly([[[0,0],[0,10],[10,10],[10,0],[0,0]]])\n    w.record(\"Square\", 100)\n\n    # Add another polygon with a hole\n    w.poly([\n        [[20,20],[20,30],[30,30],[30,20],[20,20]], # Outer ring\n        [[22,22],[22,28],[28,28],[28,22],[22,22]]  # Inner ring (hole)\n    ])\n    w.record(\"Donut\", 56)\n\nprint(f\"Shapefile '{os.path.join(output_dir, 'new_polygon.shp')}' created successfully.\")\n\n# Clean up (optional)\n# for ext in ['.shp', '.shx', '.dbf', '.prj']: # .prj might not be created by default\n#     if os.path.exists(os.path.join(output_dir, 'new_polygon' + ext)):\n#         os.remove(os.path.join(output_dir, 'new_polygon' + ext))\n#     if os.path.exists(os.path.join(output_dir, 'test_points' + ext)):\n#         os.remove(os.path.join(output_dir, 'test_points' + ext))\n# os.rmdir(output_dir)","lang":"python","description":"This quickstart demonstrates how to create a simple shapefile, write point geometries and their attributes, then read them back. It also shows how to create a polygon shapefile with multiple parts (including a hole), setting the shape type and adding fields and records. Using context managers ensures files are properly closed."},"warnings":[{"fix":"Upgrade your Python environment to 3.9+ or use pyshp versions < 3.0.0.","message":"Pyshp version 3.0.0 and later dropped support for Python 2 and Python versions up to 3.8. It now requires Python 3.9 or newer.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Consult the official documentation for updated API usage, particularly when accessing field metadata or bounding box information, and ensure your code adapts to the new object types. Refactor any code that relied on `Writer` mutating `Shapes`.","message":"Major API changes were introduced in 3.0.0. Field info tuples are now `namedtuple`s, field type codes are `FieldType` enum members, `bbox`, `mbox`, and `zbox` attributes are `Namedtuples`. The `Writer` object no longer mutates `Shapes`, and new custom subclasses for each shape type were added.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Instead of `w.records.extend(r.records())`, iterate through `r.iterShapeRecords()` and add shapes and records individually: `for shaperec in r.iterShapeRecords(): w.record(*shaperec.record); w.shape(shaperec.shape)`.","message":"In PyShp 2.x, the method for copying records from one `Reader` to a `Writer` changed. Directly using `w.records.extend(r.records())` is no longer supported for `Writer` objects.","severity":"gotcha","affected_versions":">=2.0.0, <3.0.0 (though 3.x also uses the new pattern)"},{"fix":"If encountering unexpectedly empty records, check the source shapefile's DBF structure for invalid deleted flags. Consider re-exporting the shapefile from a more compliant GIS application or manually sanitizing the DBF if possible. You might need to filter null geometries manually if the shapefile contains them.","message":"Pyshp is strict about the 'deleted flag' in DBF records. Only records with a flag of `0x20` (valid) or `0x2A` (deleted) are properly interpreted. Other values (e.g., `0x00` from some GIS software) will be interpreted as deleted, potentially leading to empty records when reading.","severity":"gotcha","affected_versions":"All versions"},{"fix":"If you require static type checking for pyshp, install the optional `pyshp-stubs` package via `pip install 'pyshp[stubs]'`.","message":"Pyshp 3.0.2 removed the `py.typed` marker file from the main package. This was done to prevent accidental type checking enforcement on unrelated projects in the same environment. For explicit type checking, an optional `pyshp-stubs` package is now provided.","severity":"gotcha","affected_versions":">=3.0.2"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}